├── .nvmrc
├── README.md
├── src
├── types
│ ├── external.d.ts
│ ├── p2.d.ts
│ ├── phaser_box2d.d.ts
│ └── pixi.d.ts
├── configs
│ ├── rules
│ │ ├── constants.ts
│ │ ├── index.ts
│ │ ├── utils.ts
│ │ ├── logic.ts
│ │ ├── layers.ts
│ │ ├── etc.ts
│ │ ├── spells.ts
│ │ └── units.ts
│ ├── objects
│ │ ├── index.ts
│ │ ├── constants.ts
│ │ ├── logic.ts
│ │ ├── terrain.ts
│ │ ├── effects.ts
│ │ ├── ui.ts
│ │ ├── spells.ts
│ │ └── units.ts
│ └── renderers.ts
├── assets
│ ├── img
│ │ ├── boss.png
│ │ ├── heart.png
│ │ ├── spell.png
│ │ ├── tree1.png
│ │ ├── tree2.png
│ │ ├── bloods.png
│ │ ├── borders.png
│ │ ├── buttons.png
│ │ ├── cursor.png
│ │ ├── demons.png
│ │ ├── effects.png
│ │ ├── loading.png
│ │ ├── sblood.png
│ │ ├── stones.png
│ │ ├── terrain.png
│ │ ├── zombies.png
│ │ ├── bossSpell.png
│ │ ├── darkblast.png
│ │ ├── effects2.png
│ │ ├── explosions.png
│ │ ├── hellfire.png
│ │ ├── mainhero.png
│ │ ├── mainmenu.jpeg
│ │ ├── powerup2.png
│ │ ├── spellicons.png
│ │ ├── bigMonsters.png
│ │ ├── frosteffect.png
│ │ └── fireballsprite.png
│ ├── music
│ │ ├── death.mp3
│ │ ├── menu.mp3
│ │ ├── battle.mp3
│ │ └── battle2.mp3
│ └── list.ts
├── engine
│ ├── index.ts
│ ├── types.ts
│ ├── sprite.ts
│ ├── object.ts
│ ├── collisions.ts
│ └── layer.ts
├── states
│ ├── index.ts
│ ├── preloading.ts
│ ├── loading.ts
│ ├── mainMenu.ts
│ └── battle.ts
├── index.ts
└── index.html
├── .prettierrc
├── .gitattributes
├── tsconfig.json
├── dev
├── server.js
└── index.ejs
├── package.json
└── .gitignore
/.nvmrc:
--------------------------------------------------------------------------------
1 | 14.15.3
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | https://grimsonland.vercel.app/
2 |
--------------------------------------------------------------------------------
/src/types/external.d.ts:
--------------------------------------------------------------------------------
1 | interface Window {
2 | game: Phaser.Game;
3 | }
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "all",
3 | "singleQuote": true
4 | }
5 |
--------------------------------------------------------------------------------
/src/configs/rules/constants.ts:
--------------------------------------------------------------------------------
1 | export enum Effects {
2 | Frozzen = 'frozzen',
3 | }
4 |
--------------------------------------------------------------------------------
/src/assets/img/boss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/boss.png
--------------------------------------------------------------------------------
/src/assets/img/heart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/heart.png
--------------------------------------------------------------------------------
/src/assets/img/spell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/spell.png
--------------------------------------------------------------------------------
/src/assets/img/tree1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/tree1.png
--------------------------------------------------------------------------------
/src/assets/img/tree2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/tree2.png
--------------------------------------------------------------------------------
/src/assets/img/bloods.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/bloods.png
--------------------------------------------------------------------------------
/src/assets/img/borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/borders.png
--------------------------------------------------------------------------------
/src/assets/img/buttons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/buttons.png
--------------------------------------------------------------------------------
/src/assets/img/cursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/cursor.png
--------------------------------------------------------------------------------
/src/assets/img/demons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/demons.png
--------------------------------------------------------------------------------
/src/assets/img/effects.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/effects.png
--------------------------------------------------------------------------------
/src/assets/img/loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/loading.png
--------------------------------------------------------------------------------
/src/assets/img/sblood.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/sblood.png
--------------------------------------------------------------------------------
/src/assets/img/stones.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/stones.png
--------------------------------------------------------------------------------
/src/assets/img/terrain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/terrain.png
--------------------------------------------------------------------------------
/src/assets/img/zombies.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/zombies.png
--------------------------------------------------------------------------------
/src/assets/music/death.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/music/death.mp3
--------------------------------------------------------------------------------
/src/assets/music/menu.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/music/menu.mp3
--------------------------------------------------------------------------------
/src/assets/img/bossSpell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/bossSpell.png
--------------------------------------------------------------------------------
/src/assets/img/darkblast.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/darkblast.png
--------------------------------------------------------------------------------
/src/assets/img/effects2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/effects2.png
--------------------------------------------------------------------------------
/src/assets/img/explosions.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/explosions.png
--------------------------------------------------------------------------------
/src/assets/img/hellfire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/hellfire.png
--------------------------------------------------------------------------------
/src/assets/img/mainhero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/mainhero.png
--------------------------------------------------------------------------------
/src/assets/img/mainmenu.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/mainmenu.jpeg
--------------------------------------------------------------------------------
/src/assets/img/powerup2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/powerup2.png
--------------------------------------------------------------------------------
/src/assets/img/spellicons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/spellicons.png
--------------------------------------------------------------------------------
/src/assets/music/battle.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/music/battle.mp3
--------------------------------------------------------------------------------
/src/assets/music/battle2.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/music/battle2.mp3
--------------------------------------------------------------------------------
/src/assets/img/bigMonsters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/bigMonsters.png
--------------------------------------------------------------------------------
/src/assets/img/frosteffect.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/frosteffect.png
--------------------------------------------------------------------------------
/src/assets/img/fireballsprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BrooklynKing/Grimsonland/HEAD/src/assets/img/fireballsprite.png
--------------------------------------------------------------------------------
/src/engine/index.ts:
--------------------------------------------------------------------------------
1 | export * from './types';
2 | export { bootstrapCollisions } from './collisions';
3 | export { GameObject } from './object';
4 | export { GameLayer } from './layer';
--------------------------------------------------------------------------------
/src/states/index.ts:
--------------------------------------------------------------------------------
1 | export { PreLoading } from './preloading';
2 | export { Loading } from './loading';
3 | export { MainMenu } from './mainMenu';
4 | export { Battle } from './battle';
5 |
6 |
--------------------------------------------------------------------------------
/src/configs/objects/index.ts:
--------------------------------------------------------------------------------
1 | export * from './spells';
2 | export * from './logic';
3 | export * from './units';
4 | export * from './effects';
5 | export * from './terrain';
6 | export * from './ui';
--------------------------------------------------------------------------------
/src/configs/rules/index.ts:
--------------------------------------------------------------------------------
1 | export * from './spells';
2 | export * from './logic';
3 | export * from './units';
4 | export * from './layers';
5 | export * from './etc';
6 |
7 | //export { GameRule } from './types';
8 |
--------------------------------------------------------------------------------
/src/configs/rules/utils.ts:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser';
2 |
3 | export const moveWithSpeed = (
4 | point: Phaser.Point,
5 | destination: Phaser.Point,
6 | speed: number
7 | ): Phaser.Point =>
8 | Phaser.Point.add(
9 | point,
10 | destination.clone().normalize().multiply(speed, speed)
11 | );
12 |
--------------------------------------------------------------------------------
/src/states/preloading.ts:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser';
2 |
3 | export class PreLoading extends Phaser.State {
4 | preload() {
5 | this.game.stage.backgroundColor = 0x0e0e0e;
6 | this.game.load.image('loading', '../assets/img/loading.png');
7 | }
8 | create() {
9 | this.game.state.start('Loading');
10 | }
11 | }
--------------------------------------------------------------------------------
/src/configs/objects/constants.ts:
--------------------------------------------------------------------------------
1 | export enum ObjectTypes {
2 | MonsterSpellElement = 'monserSpellElement',
3 | SpellEffect = 'spellEffect',
4 | SpellElement = 'spellElement',
5 | Effect = 'effect',
6 | Spell = 'spell',
7 | Player = 'player',
8 | Monster = 'monster',
9 | Controller = 'controller',
10 | Terrain = 'terrain',
11 | PowerUp = 'powerUp',
12 | UI = 'ui',
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser';
2 |
3 | import { PreLoading, Loading, Battle, MainMenu } from './states';
4 |
5 | const game = new Phaser.Game(
6 | 1024,
7 | 768,
8 | Phaser.CANVAS,
9 | 'main',
10 | PreLoading,
11 | false,
12 | false,
13 | );
14 |
15 | game.state.add('Loading', Loading);
16 | game.state.add('Battle', Battle);
17 | game.state.add('MainMenu', MainMenu);
18 |
19 | window.game = game;
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/src/configs/objects/logic.ts:
--------------------------------------------------------------------------------
1 | import * as rules from '../rules';
2 |
3 | import { ObjectTypes } from './constants';
4 |
5 | import type { GameObjectConfig } from '../../engine';
6 |
7 | export const monsterController: GameObjectConfig = {
8 | render: false,
9 | collisions: false,
10 | type: ObjectTypes.Controller,
11 | rules: [rules.monsterController],
12 | parameters: {
13 | monsterCount: [10, 25, 50, 75, 100, 150, 200, 500, 1000, 2500, 5000, 10000],
14 | monsterCooldown: 7,
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "allowSyntheticDefaultImports": true,
5 | "esModuleInterop": true,
6 | "outDir": "./dist/",
7 | "preserveConstEnums": true,
8 | "sourceMap": true,
9 | "composite": true,
10 | "strict": true,
11 |
12 | "noUnusedLocals": false,
13 | "noUnusedParameters": false,
14 | "noImplicitReturns": false,
15 | "noImplicitAny": true,
16 | "noFallthroughCasesInSwitch": true,
17 |
18 | "module": "commonjs",
19 | "moduleResolution": "node",
20 | "skipLibCheck": true,
21 | "importHelpers": true,
22 | "target": "es6",
23 | "jsx": "react",
24 | "lib": ["dom", "es2016"]
25 | },
26 | "include": ["./test/**/*.*", "./src/**/*.*"],
27 | "files": ["./src/index.ts"]
28 | }
29 |
--------------------------------------------------------------------------------
/dev/server.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const ejs = require('ejs');
3 | const express = require('express');
4 |
5 | function render(template, data) {
6 | const options = Object.assign(
7 | {
8 | debug: true,
9 | basename: '/',
10 | staticsBaseUrl: '//localhost:3200/',
11 | },
12 | data,
13 | );
14 |
15 | return ejs.render(fs.readFileSync(template, { encoding: 'utf8' }), options);
16 | }
17 |
18 | function start(port = 3000, onListen = () => {}) {
19 | const app = express();
20 |
21 | app.get('/', (req, res) => {
22 | res.send(render('./dev/index.ejs'));
23 | });
24 |
25 | app.use('/assets', express.static('./src/assets'));
26 |
27 | return app.listen(port, () => {
28 | console.log('Server is listening on port ' + port + '...');
29 | onListen();
30 | });
31 | }
32 |
33 | start();
34 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "grimsonland",
3 | "version": "1.0.0",
4 | "description": "Grimsonlad",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/BrooklynKing/Grimsonland"
8 | },
9 | "author": "Oleksii Makodzeba",
10 | "license": "MIT",
11 | "scripts": {
12 | "start": "yoshi start",
13 | "lint": "yoshi lint",
14 | "test": "",
15 | "build": "yoshi build",
16 | "release": "yoshi release"
17 | },
18 | "homepage": "",
19 | "devDependencies": {
20 | "yoshi": "^4.29.0",
21 | "typescript": "^4.1.3"
22 | },
23 | "dependencies": {
24 | "phaser": "^2.6.2"
25 | },
26 | "yoshi": {
27 | "exports": "Game",
28 | "externals": {
29 | "phaser": "Phaser",
30 | "PIXI": "PIXI"
31 | },
32 | "entry": {
33 | "game": "./index.ts"
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/configs/objects/terrain.ts:
--------------------------------------------------------------------------------
1 | import * as rules from '../rules';
2 |
3 | import { ObjectTypes } from './constants';
4 | import { object as objectRender, sprite as spriteRender } from '../renderers';
5 |
6 | import type { GameObjectConfig } from '../../engine';
7 |
8 | export const tree1: GameObjectConfig = {
9 | render: spriteRender,
10 | type: ObjectTypes.Terrain,
11 | sprite: ['tree1', [0, 0], [62, 87]],
12 | size: [62, 88],
13 | rules: [rules.dynamicZIndex],
14 | };
15 |
16 | export const tree2: GameObjectConfig = {
17 | render: spriteRender,
18 | type: ObjectTypes.Terrain,
19 | sprite: ['tree2', [0, 0], [59, 87]],
20 | size: [60, 88],
21 | rules: [rules.dynamicZIndex],
22 | };
23 |
24 | export const stones: GameObjectConfig = {
25 | type: ObjectTypes.Terrain,
26 | render: objectRender,
27 | sprite: ['stone', [0, 0], [25, 22]],
28 | size: [15, 22],
29 | rules: [rules.dynamicZIndex],
30 | };
31 |
--------------------------------------------------------------------------------
/src/states/loading.ts:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser';
2 |
3 | import { IMAGES, AUDIO } from '../assets/list';
4 |
5 | export class Loading extends Phaser.State {
6 | private text!: Phaser.Text;
7 |
8 | preload() {
9 | this.game.stage.backgroundColor = 0x0e0e0e;
10 |
11 | this.text = this.add.text(460, 250, 'LOADING', {
12 | fill: '#efefef',
13 | });
14 |
15 | this.game.load.setPreloadSprite(this.game.add.image(400, 300, 'loading'));
16 |
17 | this.game.load.spritesheet('button', '../assets/img/buttons.png', 293, 54);
18 |
19 | Object.keys(IMAGES).forEach((imageID: string) => {
20 | this.game.load.image(imageID, IMAGES[imageID as keyof typeof IMAGES]);
21 | });
22 |
23 | Object.keys(AUDIO).forEach((audioID: string) => {
24 | this.game.load.audio(audioID, AUDIO[audioID as keyof typeof AUDIO]);
25 | });
26 | }
27 |
28 | create() {
29 | this.text.destroy();
30 | this.game.state.start('MainMenu');
31 | }
32 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # Windows shortcuts
18 | *.lnk
19 |
20 | # =========================
21 | # Operating System Files
22 | # =========================
23 |
24 | # OSX
25 | # =========================
26 |
27 | .DS_Store
28 | .AppleDouble
29 | .LSOverride
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear in the root of a volume
35 | .DocumentRevisions-V100
36 | .fseventsd
37 | .Spotlight-V100
38 | .TemporaryItems
39 | .Trashes
40 | .VolumeIcon.icns
41 |
42 | # Directories potentially created on remote AFP share
43 | .AppleDB
44 | .AppleDesktop
45 | Network Trash Folder
46 | Temporary Items
47 | .apdisk
48 |
49 | dist
50 | node_modules
51 | *npm-debug.logg
52 | target
53 | maven
54 | .idea
55 | .DS_Store
56 | yarn-error.log
57 | yarn-lock.error
58 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Grimsonland
6 |
7 |
8 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/dev/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Grimsonland
6 |
7 |
8 |
39 |
40 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/engine/types.ts:
--------------------------------------------------------------------------------
1 | import { IMAGES_LIST } from "../assets/list";
2 |
3 | import type { Battle } from "../states/battle";
4 |
5 | import type { GameObject } from "./object";
6 | import type { GameLayer, OBJECTS_ID } from "./layer";
7 | export type Render = (obj: GameObject, dt: number) => void;
8 |
9 | export interface GameRule {
10 | init?(obj: GameObject | GameLayer): void;
11 | update?(obj: GameObject | GameLayer, dt: number): void;
12 | }
13 |
14 | export interface GameObjectConfig {
15 | pos?: Phaser.Point | [number, number];
16 | sprite?: [
17 | IMAGES_LIST,
18 | [number, number],
19 | [number, number],
20 | number?,
21 | Array?,
22 | string?,
23 | boolean?,
24 | number?
25 | ];
26 | size?: number[];
27 | type: string;
28 | collisions?: boolean;
29 | zIndex?: number;
30 | parameters?: { [key: string]: any };
31 | rules?: GameRule[];
32 | conditions?: GameRule[];
33 | render: Render[] | Render | false;
34 | }
35 |
36 | interface ITranslate {
37 | x: number;
38 | y: number;
39 | }
40 |
41 | export interface GameLayerConfig {
42 | id: string;
43 | background: string;
44 | state: Battle;
45 | ctx: CanvasRenderingContext2D;
46 | initList: OBJECTS_ID[];
47 | translate: ITranslate;
48 | rules: GameRule[];
49 | size: number[];
50 | init: () => void;
51 | }
52 |
--------------------------------------------------------------------------------
/src/assets/list.ts:
--------------------------------------------------------------------------------
1 | export const IMAGES = {
2 | mainmenu: "../assets/img/mainmenu.jpeg",
3 | bigMonsters: "../assets/img/bigMonsters.png",
4 | boss: "../assets/img/boss.png",
5 | bossSpell: "../assets/img/bossSpell.png",
6 | monsterBlood: "../assets/img/sblood.png",
7 | bloodEffect: "../assets/img/bloods.png",
8 | cursor: "../assets/img/cursor.png",
9 | darkblast: "../assets/img/darkblast.png",
10 | demons: "../assets/img/demons.png",
11 | effects: "../assets/img/effects.png",
12 | explosions: "../assets/img/explosions.png",
13 | fireball: "../assets/img/fireballsprite.png",
14 | hellfire: "../assets/img/hellfire.png",
15 | frostEffect: "../assets/img/frosteffect.png",
16 | pumpkin: "../assets/img/heart.png",
17 | hero: "../assets/img/mainhero.png",
18 | powerUp: "../assets/img/powerup2.png",
19 | arcaneGate: "../assets/img/spell.png",
20 | spellIcons: "../assets/img/spellicons.png",
21 | stone: "../assets/img/stones.png",
22 | terrain: "../assets/img/terrain.png",
23 | tree1: "../assets/img/tree1.png",
24 | tree2: "../assets/img/tree2.png",
25 | };
26 |
27 | export type IMAGES_LIST = keyof typeof IMAGES;
28 |
29 | export const AUDIO = {
30 | menuTheme: "../assets/music/menu.mp3",
31 | deathTheme: "../assets/music/death.mp3",
32 | battleTheme: "../assets/music/battle.mp3",
33 | };
34 |
--------------------------------------------------------------------------------
/src/states/mainMenu.ts:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser';
2 |
3 | const INFO_TEXT =
4 | ' MOVING: WASD\n AIM: MOUSE\n CAST SPELL: MOUSE CLICK OR SPACE\n SELECT SPELL: 1, 2, 3.';
5 |
6 | export class MainMenu extends Phaser.State {
7 | private menuTheme!: Phaser.Sound;
8 | private background!: Phaser.Image;
9 |
10 | init() {
11 | this.menuTheme = this.sound.add('menuTheme', 0.3, true);
12 | this.background = this.game.add.image(512, 768, 'mainmenu');
13 | this.background.anchor.set(0.5, 1);
14 | this.background.alpha = 0.8;
15 | }
16 |
17 | create() {
18 | this.generateControls();
19 |
20 | this.menuTheme.play();
21 | }
22 |
23 | generateControls() {
24 | const button = this.add.button(
25 | 512,
26 | 384,
27 | 'button',
28 | this.startGame,
29 | this,
30 | 2,
31 | 0,
32 | 1,
33 | 2
34 | );
35 | const start = this.add.text(0, 3, 'START', {
36 | fill: '#efefef',
37 | });
38 | const info = this.add.text(-300, -300, INFO_TEXT, {
39 | fontSize: '20px',
40 | fill: '#efefef',
41 | });
42 |
43 | start.anchor.setTo(0.5, 0.5);
44 | info.anchor.setTo(0.5, 0.5);
45 | button.anchor.setTo(0.5, 0.5);
46 |
47 | button.addChild(start);
48 | button.addChild(info);
49 | }
50 |
51 | startGame() {
52 | this.game.state.start('Battle');
53 | }
54 |
55 | shutdown() {
56 | this.menuTheme.stop();
57 | }
58 | }
--------------------------------------------------------------------------------
/src/configs/rules/logic.ts:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser';
2 |
3 | import { ObjectTypes } from '../objects/constants';
4 |
5 | import type { GameObject, GameRule } from '../../engine';
6 |
7 | const monsterCount = [
8 | 10, 25, 50, 75, 100, 150, 200, 500, 1000, 2500, 5000, 10000,
9 | ];
10 | const monsterCooldown = 10;
11 | export const monsterController: GameRule = {
12 | init(obj: GameObject) {
13 | obj.parameters.currentWave = 1;
14 | obj.parameters.monsterOnWave = monsterCount[obj.parameters.currentWave - 1];
15 | obj.parameters.monsterKilled = 0;
16 | obj.parameters.monsterSpawned = 0;
17 | obj.parameters.leftOnWaveId = obj.layer.addObjectByID('leftOnWaveLabel').id;
18 | },
19 | update(obj: GameObject) {
20 | const createSpawn = () => {
21 | const rect = new Phaser.Rectangle(
22 | 100 - obj.layer.translate.x,
23 | 100 - obj.layer.translate.y,
24 | 800 - obj.layer.translate.x,
25 | 550 - obj.layer.translate.y
26 | );
27 |
28 | const pos = new Phaser.Point(
29 | Math.min(1100, Math.max(50, rect.randomX)),
30 | Math.min(900, Math.max(50, rect.randomY))
31 | );
32 | const gate = obj.layer.addObjectByID('summonGate');
33 | gate.setPosition(pos);
34 | };
35 |
36 | if (obj.parameters.monsterSpawned < obj.parameters.monsterOnWave) {
37 | if (!obj.parameters.currentMonsterCooldown) {
38 | createSpawn();
39 |
40 | obj.parameters.monsterSpawned = obj.parameters.monsterSpawned + 1;
41 | obj.parameters.currentMonsterCooldown = monsterCooldown;
42 | } else {
43 | obj.parameters.currentMonsterCooldown &&
44 | obj.parameters.currentMonsterCooldown--;
45 | }
46 | }
47 | if (
48 | !obj.layer.getObjectsByType(ObjectTypes.Monster).length &&
49 | obj.parameters.monsterKilled < obj.parameters.monsterSpawned
50 | ) {
51 | obj.parameters.monsterSpawned = obj.parameters.monsterKilled;
52 | } else {
53 | if (obj.parameters.monsterKilled >= obj.parameters.monsterOnWave) {
54 | obj.parameters.currentWave = obj.parameters.currentWave + 1;
55 | obj.parameters.monsterSpawned = 0;
56 | obj.parameters.monsterOnWave =
57 | monsterCount[obj.parameters.currentWave - 1];
58 | obj.parameters.monsterKilled = 0;
59 | }
60 | }
61 |
62 | const leftOnWave = obj.layer.getObjectByID(obj.parameters.leftOnWaveId);
63 | leftOnWave.parameters.text = `LEFT ON THIS WAVE: ${obj.parameters.monsterKilled + '/' + obj.parameters.monsterOnWave}`;
64 | },
65 | };
66 |
--------------------------------------------------------------------------------
/src/configs/rules/layers.ts:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser';
2 |
3 | import { ObjectTypes } from '../objects/constants';
4 |
5 | import type { GameLayer, GameRule } from '../../engine';
6 |
7 | const TREES_COUNT = 100;
8 | const STONES_COUNT = 100;
9 | const HEART_SPAWN_COOLDOWN = 400;
10 | const EXP_SPAWN_COOLDOWN = 400;
11 |
12 | const getRandomPointInArea = (obj: GameLayer) => {
13 | return [
14 | Math.round(Math.random() * obj.size![0]),
15 | Math.round(Math.random() * obj.size![1]),
16 | ];
17 | };
18 |
19 | export const randomTrees: GameRule = {
20 | init(obj: GameLayer) {
21 | for (let i = 0; i < TREES_COUNT; i++) {
22 | const point = getRandomPointInArea(obj);
23 | const tree = obj.addObjectByID(Math.random() > 0.5 ? 'tree2' : 'tree1');
24 | tree.setPosition(new Phaser.Point(point[0], point[1]));
25 | }
26 |
27 | for (let i = 0; i < STONES_COUNT; i++) {
28 | const point = getRandomPointInArea(obj);
29 | const stone = obj.addObjectByID('stones');
30 | stone.setPosition(new Phaser.Point(point[0], point[1]));
31 | }
32 | },
33 | };
34 |
35 | export const spawnHeart: GameRule = {
36 | update(obj: GameLayer) {
37 | if (!obj.parameters.spawnHeartCurrentCooldown) {
38 | const rect = new Phaser.Rectangle(50, 50, 1104, 868);
39 | const heart = obj.addObjectByID('heart');
40 | heart.setPosition(new Phaser.Point(rect.randomX, rect.randomY));
41 |
42 | obj.parameters.spawnHeartCurrentCooldown = HEART_SPAWN_COOLDOWN;
43 | } else {
44 | obj.parameters.spawnHeartCurrentCooldown--;
45 | }
46 | },
47 | };
48 |
49 | export const spawnExp: GameRule = {
50 | update(obj: GameLayer) {
51 | if (!obj.parameters.spawnExpCurrentCooldown) {
52 | const rect = new Phaser.Rectangle(100, 100, 1000, 750);
53 | const exp = obj.addObjectByID('powerup');
54 | exp.setPosition(new Phaser.Point(rect.randomX, rect.randomY));
55 |
56 | obj.parameters.spawnExpCurrentCooldown = EXP_SPAWN_COOLDOWN;
57 | } else {
58 | obj.parameters.spawnExpCurrentCooldown--;
59 | }
60 | },
61 | };
62 |
63 | export const goWithPlayer: GameRule = {
64 | update(obj: GameLayer, dt: number) {
65 | const player = obj.getObjectsByType(ObjectTypes.Player)[0];
66 | const px = ((player.pos.x + obj.translate.x) / 1024) * 100;
67 | const py = ((player.pos.y + obj.translate.y) / 768) * 100;
68 |
69 | if (px < 30) {
70 | if (obj.translate.x < 0) {
71 | obj.translate.x += Math.round(player.parameters.speed * dt);
72 | }
73 | }
74 | if (px > 70) {
75 | if (obj.translate.x > -300) {
76 | obj.translate.x -= Math.round(player.parameters.speed * dt);
77 | }
78 | }
79 |
80 | if (py < 25) {
81 | if (obj.translate.y < 0) {
82 | obj.translate.y += Math.round(player.parameters.speed * dt);
83 | }
84 | }
85 | if (py > 75) {
86 | if (obj.translate.y > -300) {
87 | obj.translate.y -= Math.round(player.parameters.speed * dt);
88 | }
89 | }
90 | },
91 | };
92 |
--------------------------------------------------------------------------------
/src/engine/sprite.ts:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser';
2 |
3 | export interface ISpriteConfig {
4 | cache: Phaser.Cache;
5 | url: string;
6 | pos: Phaser.Point;
7 | size: [number, number];
8 | speed?: number;
9 | frames?: number[];
10 | dir?: string;
11 | once?: boolean;
12 | degree?: number;
13 | }
14 |
15 | export class Sprite {
16 | size: [number, number];
17 | done: boolean;
18 |
19 | private pos: Phaser.Point;
20 | private speed: number;
21 | private degree: number;
22 | private cache: Phaser.Cache;
23 | private url: string;
24 | private frames: number[];
25 | private frameIndex: number;
26 | private dir: string;
27 | private once: boolean;
28 | private defaultPosition: Phaser.Point;
29 |
30 | constructor({
31 | cache,
32 | pos,
33 | size,
34 | speed,
35 | frames,
36 | url,
37 | dir,
38 | once,
39 | degree,
40 | }: ISpriteConfig) {
41 | this.cache = cache;
42 | this.pos = pos;
43 | this.defaultPosition = this.pos.clone();
44 | this.size = size;
45 | this.speed = typeof speed === 'number' ? speed : 0;
46 | this.frames = frames || [];
47 | this.frameIndex = 0;
48 | this.url = url;
49 | this.dir = dir || 'horizontal';
50 | this.once = Boolean(once);
51 | this.degree = degree || 0;
52 | this.done = false;
53 | }
54 |
55 | update(dt: number) {
56 | this.frameIndex += this.speed * dt;
57 | }
58 |
59 | setDegree(degree: number) {
60 | this.degree = degree;
61 | }
62 |
63 | rotateToDirection(direction: Phaser.Point) {
64 | const angle = direction.angle(new Phaser.Point(0, 0), true);
65 | const { x: defaultX, y: defaultY } = this.defaultPosition;
66 |
67 | if (angle > 135 || angle < -135) {
68 | this.pos.setTo(defaultX, defaultY + 2 * this.size[1]);
69 | } else if (angle < 135 && angle > 45) {
70 | this.pos.setTo(defaultX, defaultY + 3 * this.size[1]);
71 | } else if (angle < 45 && angle > -45) {
72 | this.pos.setTo(defaultX, defaultY + this.size[1]);
73 | } else {
74 | this.pos.setTo(defaultX, defaultY);
75 | }
76 | }
77 |
78 | render(ctx: CanvasRenderingContext2D) {
79 | let frame;
80 | let x = this.pos.x;
81 | let y = this.pos.y;
82 |
83 | if (this.speed > 0) {
84 | const max = this.frames.length;
85 | const idx = Math.floor(this.frameIndex);
86 |
87 | frame = this.frames[idx % max];
88 |
89 | if (this.once && idx >= max) {
90 | this.done = true;
91 | return;
92 | }
93 | } else {
94 | frame = 0;
95 | }
96 |
97 | if (this.dir === 'vertical') {
98 | y += frame * this.size[1];
99 | } else {
100 | x += frame * this.size[0];
101 | }
102 |
103 | ctx.rotate(this.degree);
104 | ctx.drawImage(
105 | this.cache.getImage(this.url),
106 | x,
107 | y,
108 | this.size[0],
109 | this.size[1],
110 | Math.round(-this.size[0] / 2),
111 | Math.round(-this.size[1] / 2),
112 | this.size[0],
113 | this.size[1]
114 | );
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/configs/objects/effects.ts:
--------------------------------------------------------------------------------
1 | import * as rules from '../rules';
2 | import { ObjectTypes } from './constants';
3 | import { object as objectRender, fog as fogRender, sprite as spriteRender } from '../renderers';
4 |
5 | import type { GameObjectConfig } from '../../engine';
6 |
7 | export const mbullet: GameObjectConfig = {
8 | zIndex: 3,
9 | collisions: true,
10 | sprite: ['darkblast', [0, 0], [38, 38], 12, [0, 1, 2, 3]],
11 | type: ObjectTypes.MonsterSpellElement,
12 | render: objectRender,
13 | size: [32, 32],
14 | conditions: [rules.damageOnPlayerCollision, rules.destroyOnPlayerCollision],
15 | parameters: {
16 | power: 8,
17 | speed: 100,
18 | },
19 | rules: [
20 | rules.destroyAfterLeavingLayer,
21 | rules.moveToDirection,
22 | rules.dynamicZIndex,
23 | ],
24 | };
25 |
26 | export const mbullet2: GameObjectConfig = {
27 | zIndex: 3,
28 | collisions: true,
29 | sprite: ['bossSpell', [0, 0], [30, 26], 10, [0, 1, 2]],
30 | type: ObjectTypes.MonsterSpellElement,
31 | render: objectRender,
32 | size: [28, 24],
33 | conditions: [rules.monsterBoss2Bullet],
34 | parameters: {
35 | power: 15,
36 | cooldown: 100,
37 | speed: 200,
38 | },
39 | rules: [
40 | rules.destroyAfterLeavingLayer,
41 | rules.setDirectionToPlayer,
42 | rules.rotateByDirection,
43 | rules.moveToDirection,
44 | rules.dynamicZIndex,
45 | ],
46 | };
47 |
48 | export const blood: GameObjectConfig = {
49 | render: spriteRender,
50 | type: ObjectTypes.Effect,
51 | zIndex: 2,
52 | sprite: ['monsterBlood', [0, 0], [32, 13]],
53 | parameters: {
54 | cooldown: 500,
55 | },
56 | rules: [rules.removeOnCooldown],
57 | };
58 |
59 | export const bloodSpray: GameObjectConfig = {
60 | render: spriteRender,
61 | type: ObjectTypes.Effect,
62 | zIndex: 2,
63 | sprite: [
64 | 'bloodEffect',
65 | [0, 0],
66 | [64, 64],
67 | 15,
68 | [0, 1, 2, 3, 4],
69 | undefined,
70 | true,
71 | 0.785,
72 | ],
73 | rules: [rules.destroyAfterSpriteDone, rules.dynamicZIndex],
74 | };
75 |
76 | export const explosion: GameObjectConfig = {
77 | type: ObjectTypes.Effect,
78 | render: objectRender,
79 | size: [39, 39],
80 | sprite: [
81 | 'explosions',
82 | [0, 0],
83 | [39, 39],
84 | 16,
85 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
86 | undefined,
87 | true,
88 | ],
89 | rules: [rules.destroyAfterSpriteDone, rules.dynamicZIndex],
90 | };
91 |
92 | export const monsterExplosion: GameObjectConfig = {
93 | render: objectRender,
94 | collisions: true,
95 | type: ObjectTypes.SpellEffect,
96 | conditions: [rules.monsterExplosion],
97 | size: [39, 39],
98 | sprite: [
99 | 'explosions',
100 | [0, 0],
101 | [39, 39],
102 | 16,
103 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
104 | undefined,
105 | true,
106 | ],
107 | rules: [rules.destroyAfterSpriteDone, rules.dynamicZIndex],
108 | };
109 |
110 | export const spellExplosion: GameObjectConfig = {
111 | render: objectRender,
112 | collisions: true,
113 | type: ObjectTypes.SpellEffect,
114 | conditions: [rules.spellExplosion],
115 | size: [39, 39],
116 | sprite: [
117 | 'explosions',
118 | [0, 0],
119 | [39, 39],
120 | 16,
121 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
122 | undefined,
123 | true,
124 | ],
125 | rules: [rules.destroyAfterSpriteDone, rules.dynamicZIndex],
126 | };
127 |
128 | export const fog: GameObjectConfig = {
129 | render: fogRender,
130 | zIndex: 2500,
131 | type: ObjectTypes.Effect,
132 | };
133 |
--------------------------------------------------------------------------------
/src/configs/objects/ui.ts:
--------------------------------------------------------------------------------
1 | import { ObjectTypes } from './constants';
2 | import { ui as uiRender, text as textRender, expBar as expBarRender } from '../renderers';
3 |
4 | import type { GameObject, GameObjectConfig, GameRule } from '../../engine';
5 |
6 | const bindPositionToMouse: GameRule = {
7 | update(obj: GameObject) {
8 | const mousePosition = new Phaser.Point(
9 | obj.layer.game.input.mousePointer.x,
10 | obj.layer.game.input.mousePointer.y
11 | );
12 |
13 | obj.setPosition(mousePosition.clone());
14 | },
15 | };
16 |
17 | export const cursor: GameObjectConfig = {
18 | type: ObjectTypes.UI,
19 | zIndex: 3000,
20 | render: uiRender,
21 | pos: [400, 350],
22 | sprite: ['cursor', [0, 0], [30, 30]],
23 | rules: [bindPositionToMouse],
24 | };
25 |
26 |
27 | const countMonsterKilled: GameRule = {
28 | update(obj: GameObject) {
29 | obj.parameters.text = `SCORE: ${obj.layer.state.parameters.monstersKilled || 0}`;
30 | },
31 | };
32 |
33 | export const counter: GameObjectConfig = {
34 | type: ObjectTypes.UI,
35 | zIndex: 3000,
36 | pos: [5, 13],
37 | render: textRender,
38 | parameters: {
39 | weight: 'bold',
40 | color: '#DAA520',
41 | size: 14,
42 | },
43 | rules: [countMonsterKilled],
44 | };
45 |
46 | export const leftOnWaveLabel: GameObjectConfig = {
47 | type: ObjectTypes.UI,
48 | zIndex: 3000,
49 | pos: [5, 100],
50 | render: textRender,
51 | parameters: {
52 | weight: 'bold',
53 | color: '#DAA520',
54 | size: 14,
55 | },
56 | };
57 |
58 | const levelRule: GameRule = {
59 | update(obj: GameObject) {
60 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
61 |
62 | obj.parameters.text = `LEVEL: ${player.parameters.level}`;
63 | },
64 | };
65 |
66 | export const level: GameObjectConfig = {
67 | type: ObjectTypes.UI,
68 | zIndex: 3000,
69 | pos: [35, 45],
70 | render: expBarRender,
71 | parameters: {
72 | weight: 'bold',
73 | color: '#EFEFEF',
74 | size: 14,
75 | },
76 | rules: [levelRule],
77 | };
78 |
79 |
80 | const timerRule: GameRule = {
81 | update(obj: GameObject) {
82 | obj.parameters.text = `TIMER: ${(obj.layer.state.parameters.gameTimer++ / 60).toFixed(2)}`;
83 | },
84 | };
85 |
86 | export const timer: GameObjectConfig = {
87 | type: ObjectTypes.UI,
88 | zIndex: 3000,
89 | pos: [5, 23],
90 | render: textRender,
91 | parameters: {
92 | weight: 'bold',
93 | color: '#DAA520',
94 | size: 14,
95 | },
96 | rules: [timerRule],
97 | };
98 |
99 | const bestTimeRule: GameRule = {
100 | init(obj: GameObject) {
101 | obj.parameters.text = `BEST TIME: ${(obj.layer.state.parameters.bestTime / 60).toFixed(2)}`;
102 | },
103 | };
104 |
105 | export const bestTime: GameObjectConfig = {
106 | type: ObjectTypes.UI,
107 | pos: [5, 370],
108 | zIndex: 3000,
109 | render: textRender,
110 | parameters: {
111 | weight: 'bold',
112 | color: '#DAA520',
113 | size: 14,
114 | },
115 | rules: [bestTimeRule],
116 | };
117 |
118 | const bestScoreRule: GameRule = {
119 | init(obj: GameObject) {
120 | obj.parameters.text =`BEST SCORE: ${obj.layer.state.parameters.bestScore}`;
121 | },
122 | };
123 |
124 | export const bestScore: GameObjectConfig = {
125 | type: ObjectTypes.UI,
126 | pos: [5, 380],
127 | zIndex: 3000,
128 | render: textRender,
129 | parameters: {
130 | weight: 'bold',
131 | color: '#DAA520',
132 | size: 14,
133 | },
134 | rules: [bestScoreRule],
135 | };
136 |
--------------------------------------------------------------------------------
/src/configs/objects/spells.ts:
--------------------------------------------------------------------------------
1 | import * as rules from '../rules';
2 | import { ObjectTypes } from './constants';
3 | import { object as objectRender, spell as spellRender } from '../renderers';
4 |
5 | import type { GameObjectConfig } from '../../engine';
6 |
7 | export const fireballSpell: GameObjectConfig = {
8 | zIndex: 5000,
9 | sprite: ['spellIcons', [0, 0], [32, 32]],
10 | pos: [449, 748],
11 |
12 | size: [32, 32],
13 | render: spellRender,
14 | parameters: {
15 | bulletsFired: 0,
16 | cooldown: 20,
17 | },
18 | type: ObjectTypes.Spell,
19 | rules: [rules.fireball],
20 | };
21 |
22 | export const hellfireSpell: GameObjectConfig = {
23 | zIndex: 5000,
24 | sprite: ['spellIcons', [96, 0], [32, 32]],
25 | pos: [491, 748],
26 |
27 | size: [32, 32],
28 | render: spellRender,
29 | parameters: {
30 | bulletsFired: 0,
31 | cooldown: 800,
32 | },
33 | type: ObjectTypes.Spell,
34 | rules: [rules.hellfire],
35 | };
36 |
37 | export const frostShardSpell: GameObjectConfig = {
38 | zIndex: 5000,
39 | sprite: ['spellIcons', [224, 96], [32, 32]],
40 | pos: [533, 748],
41 | size: [32, 32],
42 | render: spellRender,
43 | parameters: {
44 | shardsFired: 0,
45 | cooldown: 500,
46 | },
47 | type: ObjectTypes.Spell,
48 | rules: [rules.frostShard],
49 | };
50 |
51 | export const teleportSpell: GameObjectConfig = {
52 | zIndex: 5000,
53 | sprite: ['spellIcons', [64, 32], [32, 32]],
54 | pos: [575, 748],
55 | size: [32, 32],
56 | render: spellRender,
57 | parameters: {
58 | power: 200,
59 | teleportGates: 0,
60 | cooldown: 200,
61 | },
62 | type: ObjectTypes.Spell,
63 | rules: [rules.teleport],
64 | };
65 |
66 | export const teleportGate: GameObjectConfig = {
67 | zIndex: 0,
68 | render: objectRender,
69 | sprite: ['arcaneGate', [0, 0], [32, 32], 7, [0, 1]],
70 | pos: [466, 580],
71 | size: [32, 32],
72 | parameters: {
73 | cooldown: 200,
74 | },
75 | type: ObjectTypes.SpellElement,
76 | rules: [rules.removeOnCooldown, rules.dynamicZIndex],
77 | };
78 |
79 | export const bullet: GameObjectConfig = {
80 | zIndex: 3,
81 | collisions: true,
82 | render: objectRender,
83 | sprite: ['fireball', [0, 0], [33, 33], 16, [0, 1, 2, 3]],
84 | size: [25, 25],
85 | type: ObjectTypes.SpellElement,
86 | parameters: {
87 | power: 10,
88 | cooldown: 100,
89 | speed: 300,
90 | },
91 | conditions: [rules.bulletMonsterCollision],
92 | rules: [
93 | rules.destroyAfterLeavingLayer,
94 | rules.moveToDirection,
95 | rules.dynamicZIndex,
96 | rules.explosionOnCooldown,
97 | ],
98 | };
99 |
100 | export const hellfireTube: GameObjectConfig = {
101 | zIndex: 3,
102 | collisions: true,
103 | render: objectRender,
104 | sprite: [
105 | 'hellfire',
106 | [0, 0],
107 | [21, 58],
108 | 14,
109 | [2, 3, 4, 4, 3, 2, 2, 3, 4, 4, 3, 2, 2, 3, 4, 4, 3, 2],
110 | undefined,
111 | false,
112 | ],
113 | size: [50, 50],
114 | type: ObjectTypes.SpellElement,
115 | parameters: {
116 | power: 10,
117 | cooldown: 150,
118 | speed: 300,
119 | },
120 | conditions: [rules.hellTubeMonsterCollision],
121 | rules: [rules.dynamicZIndex, rules.explosionOnCooldown],
122 | };
123 |
124 | export const frostShard: GameObjectConfig = {
125 | zIndex: 3,
126 | render: objectRender,
127 | collisions: true,
128 | sprite: ['effects', [96, 0], [32, 32], 10, [0, 1, 2]],
129 | type: ObjectTypes.SpellElement,
130 | size: [500, 500],
131 | parameters: {
132 | power: 60,
133 | cooldown: 200,
134 | },
135 | conditions: [rules.slowEnemies],
136 | rules: [rules.removeOnCooldown, rules.dynamicZIndex],
137 | };
138 |
--------------------------------------------------------------------------------
/src/engine/object.ts:
--------------------------------------------------------------------------------
1 | import { Sprite } from './sprite';
2 |
3 | import type { GameObjectConfig, GameRule, Render } from './types';
4 | import type { GameLayer } from './layer';
5 |
6 | export class GameObject {
7 | id: string;
8 | layer: GameLayer;
9 | pos: Phaser.Point;
10 | sprite?: Sprite;
11 | size?: number[];
12 | type: string;
13 | zIndex: number;
14 | shouldCheckCollisions: boolean;
15 | collisions: {
16 | objects: GameObject[];
17 | cells: any[];
18 | };
19 | private rules: GameRule[];
20 | private conditions: GameRule[];
21 | private renderers: Render[];
22 |
23 | parameters: { [key: string]: any };
24 | readonly defaultParameters: { readonly [key: string]: any };
25 |
26 | constructor(config: GameObjectConfig & { id: string; layer: GameLayer }) {
27 | this.layer = config.layer;
28 | if (config.pos instanceof Phaser.Point) {
29 | this.pos = config.pos.clone();
30 | } else {
31 | if (config.pos) {
32 | this.pos = new Phaser.Point(config.pos[0], config.pos[1]);
33 | } else {
34 | this.pos = new Phaser.Point();
35 | }
36 | }
37 | this.id = config.id;
38 |
39 | if (config.size) {
40 | this.size = config.size;
41 | }
42 |
43 | if (config.sprite) {
44 | this.sprite = new Sprite({
45 | cache: this.layer.game.cache,
46 | url: config.sprite[0],
47 | pos: new Phaser.Point(...config.sprite[1]),
48 | size: config.sprite[2],
49 | speed: config.sprite[3],
50 | frames: config.sprite[4],
51 | dir: config.sprite[5],
52 | once: config.sprite[6],
53 | degree: config.sprite[7],
54 | });
55 |
56 | this.size = config.size || this.sprite.size;
57 | } else if (config.size) {
58 | this.size = config.size;
59 | }
60 |
61 | this.type = config.type || 'default';
62 |
63 | this.zIndex = config.zIndex || 0;
64 | this.parameters = (config.parameters && { ...config.parameters }) || {};
65 | this.defaultParameters = { ...this.parameters };
66 |
67 | this.renderers = config.render
68 | ? Array.isArray(config.render)
69 | ? config.render
70 | : [config.render]
71 | : [];
72 |
73 | this.rules = [];
74 | const rulesForInit = config.rules || [];
75 | rulesForInit.forEach((rule) => {
76 | this.addRule(rule);
77 | });
78 |
79 | this.conditions = [];
80 | const conditionsForInit = config.conditions || [];
81 | conditionsForInit.forEach((condition) => {
82 | this.addCondition(condition);
83 | });
84 |
85 | this.collisions = {
86 | objects: [],
87 | cells: [],
88 | };
89 | this.shouldCheckCollisions = Boolean(config.collisions);
90 |
91 | if (this.shouldCheckCollisions) {
92 | this.layer.state.collisions.updateObject(this);
93 | }
94 | }
95 |
96 | render(dt: number) {
97 | this.renderers.forEach((renderer) => renderer(this, dt));
98 | }
99 |
100 | update(dt: number) {
101 | this.rules.forEach((rule) => rule.update?.(this, dt));
102 | }
103 |
104 | updateConditions(dt: number) {
105 | this.conditions.forEach((condition) => condition.update?.(this, dt));
106 | }
107 |
108 | updateCollisions() {
109 | if (this.shouldCheckCollisions) {
110 | this.collisions.objects = [];
111 | this.layer.state.collisions.updateObject(this);
112 | }
113 | }
114 |
115 | setPosition(point: Phaser.Point) {
116 | this.pos.x = point.x;
117 | this.pos.y = point.y;
118 | }
119 |
120 | addRule(rule: GameRule) {
121 | rule.init?.(this);
122 |
123 | this.rules.push(rule);
124 | }
125 |
126 | addCondition(condition: GameRule) {
127 | condition.init?.(this);
128 |
129 | this.conditions.push(condition);
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/engine/collisions.ts:
--------------------------------------------------------------------------------
1 | import type { GameObject } from "./object";
2 |
3 | export const bootstrapCollisions = (config: {
4 | n: number;
5 | width: number;
6 | height: number;
7 | }) => {
8 | const n = config.n || 6;
9 | const width = config.width || 800;
10 | const height = config.height || 600;
11 | const sizeX = width >> n;
12 | const sizeY = height >> n;
13 | const cellGrid = new Array(sizeX * sizeY);
14 |
15 | const generateMap = () => {
16 | for (let i = 0; i < cellGrid.length; i++) {
17 | cellGrid[i] = [];
18 | }
19 | };
20 |
21 | const getCell = (point: number[]) => {
22 | return point[0] + point[1] * sizeY;
23 | };
24 |
25 | const removeObject = (object: GameObject) => {
26 | const oldCells = object.collisions.cells;
27 |
28 | for (let i = 0; i < oldCells.length; i++) {
29 | cellGrid[oldCells[i]] &&
30 | cellGrid[oldCells[i]].splice(cellGrid[oldCells[i]].indexOf(object), 1);
31 | }
32 | };
33 |
34 | const getPointsOfObject = (object: GameObject) => {
35 | const pos = object.pos!;
36 | const size = object.size!;
37 | const cells = [];
38 | const xIndex = size[0] >> n;
39 | const yIndex = size[1] >> n;
40 |
41 | for (let i = 0; i < 2 + xIndex; i++) {
42 | for (let j = 0; j < 2 + yIndex; j++) {
43 | cells.push(
44 | getCell([
45 | (pos.x - size[0] / 2 + i * (size[0] / (1 + xIndex))) >> n,
46 | (pos.y - size[1] / 2 + j * (size[1] / (1 + yIndex))) >> n,
47 | ])
48 | );
49 | }
50 | }
51 |
52 | return cells;
53 | };
54 |
55 | const updateObject = (object: GameObject) => {
56 | const cells = getPointsOfObject(object);
57 | const oldCells = object.collisions.cells;
58 |
59 | for (let i = 0; i < cells.length; i++) {
60 | if (oldCells[i] !== cells[i]) {
61 | cellGrid[oldCells[i]] &&
62 | cellGrid[oldCells[i]].splice(
63 | cellGrid[oldCells[i]].indexOf(object),
64 | 1
65 | );
66 | cellGrid[cells[i]] &&
67 | cellGrid[cells[i]].indexOf(object) === -1 &&
68 | cellGrid[cells[i]].push(object);
69 | oldCells[i] = cells[i];
70 | } else {
71 | cellGrid[cells[i]] &&
72 | cellGrid[cells[i]].indexOf(object) === -1 &&
73 | cellGrid[cells[i]].push(object);
74 | }
75 | }
76 | };
77 |
78 | const checkCollisions = () => {
79 | for (let i = 0; i <= sizeX; i++) {
80 | for (let j = 0; j <= sizeY; j++) {
81 | if (cellGrid[getCell([i, j])]) {
82 | const objects = cellGrid[getCell([i, j])];
83 | const length = objects.length;
84 |
85 | for (let k = 0; k < length; k++) {
86 | for (let l = k + 1; l < length; l++) {
87 | if (
88 | boxCollides(
89 | objects[k].pos,
90 | objects[k].size,
91 | objects[l].pos,
92 | objects[l].size
93 | )
94 | ) {
95 | objects[k].collisions.objects.indexOf(objects[l]) === -1 &&
96 | objects[k].collisions.objects.push(objects[l]);
97 | objects[l].collisions.objects.indexOf(objects[k]) === -1 &&
98 | objects[l].collisions.objects.push(objects[k]);
99 | }
100 | }
101 | }
102 | }
103 | }
104 | }
105 | };
106 |
107 | const collides = (
108 | x: number,
109 | y: number,
110 | width: number,
111 | height: number,
112 | x2: number,
113 | y2: number,
114 | width2: number,
115 | height2: number
116 | ) => x < x2 + width2 && x + width > x2 && y < y2 + height2 && y + height > y2;
117 |
118 | const boxCollides = (
119 | pos: Phaser.Point,
120 | size: number[],
121 | pos2: Phaser.Point,
122 | size2: number[]
123 | ) =>
124 | collides(
125 | pos.x - size[0] / 2,
126 | pos.y - size[1] / 2,
127 | size[0],
128 | size[1],
129 | pos2.x - size2[0] / 2,
130 | pos2.y - size2[1] / 2,
131 | size2[0],
132 | size2[1]
133 | );
134 |
135 | generateMap();
136 |
137 | return {
138 | cellGrid: cellGrid,
139 | updateObject: updateObject,
140 | removeObject: removeObject,
141 | check: checkCollisions,
142 | clear: generateMap,
143 | };
144 | };
145 |
--------------------------------------------------------------------------------
/src/states/battle.ts:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser';
2 |
3 | import { bootstrapCollisions, GameLayer } from '../engine';
4 | import {
5 | randomTrees,
6 | spawnExp,
7 | spawnHeart,
8 | goWithPlayer,
9 | } from '../configs/rules/layers';
10 |
11 | import type { GameLayerConfig } from '../engine';
12 |
13 | const LAYER_CONFIG: Omit = {
14 | id: 'mainLayer',
15 | size: [1324, 1068],
16 | background: 'terrain',
17 | initList: [
18 | 'player',
19 | 'cursor',
20 | 'counter',
21 | 'timer',
22 | 'bestTime',
23 | 'fireballSpell',
24 | 'hellfireSpell',
25 | 'frostShardSpell',
26 | 'teleportSpell',
27 | 'bestScore',
28 | 'level',
29 | 'fog',
30 | 'monsterController',
31 | ],
32 | translate: {
33 | x: -150,
34 | y: -150,
35 | },
36 | rules: [randomTrees, spawnExp, spawnHeart, goWithPlayer],
37 | };
38 |
39 | export class Battle extends Phaser.State {
40 | private battleTheme!: Phaser.Sound;
41 | private deathTheme!: Phaser.Sound;
42 |
43 | private restartButton!: Phaser.Button;
44 | private restartText!: Phaser.Text;
45 |
46 | private bitmap!: Phaser.BitmapData;
47 | private gameLayer!: GameLayer;
48 | collisions!: ReturnType;
49 |
50 | parameters!: {
51 | bestTime: number;
52 | gameTimer: number;
53 | monstersKilled: number;
54 | bestScore: number;
55 | };
56 |
57 | private pauseFlag!: boolean;
58 |
59 | init() {
60 | this.battleTheme = this.sound.add('battleTheme', 0.3, true);
61 | this.deathTheme = this.sound.add('deathTheme', 0.3, true);
62 | }
63 |
64 | create() {
65 | this.pauseFlag = false;
66 |
67 | this.collisions = bootstrapCollisions({
68 | n: 6,
69 | width: 1500,
70 | height: 1200,
71 | });
72 |
73 | this.initGameParameters();
74 | this.initGameLayer();
75 | this.initControls();
76 |
77 | this.game.renderer.view.classList.add('no-pointer');
78 | this.battleTheme.play();
79 | }
80 |
81 | initControls() {
82 | this.restartButton = this.add.button(
83 | 512,
84 | 384,
85 | 'button',
86 | this.restart,
87 | this,
88 | 2,
89 | 0,
90 | 1,
91 | 2
92 | );
93 |
94 | this.restartText = this.add.text(510, 335, 'YOU DIED!', {
95 | fill: '#EF0000',
96 | });
97 | this.restartText.anchor.setTo(0.5, 0.5);
98 | this.restartText.kill();
99 |
100 | this.restartButton.addChild(
101 | this.add.text(-65, -15, 'RESTART', {
102 | fill: '#efefef',
103 | })
104 | );
105 | this.restartButton.anchor.setTo(0.5, 0.5);
106 | this.restartButton.kill();
107 | }
108 |
109 | initGameParameters() {
110 | const bestTimeFromStorage = localStorage.getItem('bestTime');
111 | const bestScoreFromStorage = localStorage.getItem('bestScore');
112 | this.parameters = {
113 | monstersKilled: 0,
114 | gameTimer: 0,
115 | bestTime: bestTimeFromStorage ? parseInt(bestTimeFromStorage) || 0 : 0,
116 | bestScore: bestScoreFromStorage ? parseInt(bestScoreFromStorage) || 0 : 0,
117 | };
118 | }
119 |
120 | initGameLayer() {
121 | this.bitmap = this.add.bitmapData(
122 | this.game.canvas.width,
123 | this.game.canvas.height,
124 | 'battleBitmap'
125 | );
126 |
127 | this.add.image(0, 0, this.bitmap);
128 |
129 | this.gameLayer = new GameLayer({
130 | ...LAYER_CONFIG,
131 | init() {
132 | this.state.parameters.monstersKilled = 0;
133 | this.state.parameters.gameTimer = 0;
134 | },
135 | state: this,
136 | ctx: this.bitmap.ctx,
137 | });
138 | this.gameLayer.init();
139 | }
140 |
141 | stopBattle() {
142 | this.updateBestScores();
143 | this.battleTheme.stop();
144 | this.deathTheme.play();
145 |
146 | this.restartButton.revive();
147 | this.restartText.revive();
148 | this.game.renderer.view.classList.remove('no-pointer');
149 |
150 | this.pauseFlag = true;
151 | }
152 |
153 | updateBestScores() {
154 | if (this.parameters.gameTimer > this.parameters.bestTime) {
155 | this.parameters.bestTime = this.parameters.gameTimer;
156 |
157 | localStorage.setItem('bestTime', this.parameters.bestTime.toString());
158 | }
159 | if (this.parameters.monstersKilled > this.parameters.bestScore) {
160 | this.parameters.bestScore = this.parameters.monstersKilled;
161 |
162 | localStorage.setItem('bestScore', this.parameters.bestScore.toString());
163 | }
164 | }
165 |
166 | prepareForRender() {
167 | if (this.pauseFlag === true) {
168 | this.gameLayer.render(0);
169 | this.bitmap.rect(
170 | 0,
171 | 0,
172 | this.game.canvas.width,
173 | this.game.canvas.height,
174 | 'rgba(10,0,0,0.5)'
175 | );
176 | } else {
177 | this.gameLayer.update(this.game.time.physicsElapsed);
178 | this.gameLayer.render(this.game.time.physicsElapsed);
179 | }
180 | }
181 |
182 | restart() {
183 | this.pauseFlag = false;
184 |
185 | this.battleTheme.play();
186 | this.deathTheme.stop();
187 |
188 | this.collisions.clear();
189 |
190 | this.restartButton.kill();
191 | this.restartText.kill();
192 | this.game.renderer.view.classList.add('no-pointer');
193 |
194 | this.gameLayer.clearLayer();
195 | this.gameLayer.init();
196 | }
197 |
198 | update() {
199 | this.prepareForRender();
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/src/configs/objects/units.ts:
--------------------------------------------------------------------------------
1 | import * as rules from '../rules';
2 |
3 | import { ObjectTypes } from './constants';
4 | import { unit as unitRender, object as objectRender, sprite as spriteRender } from '../renderers';
5 |
6 | import type { GameObjectConfig } from '../../engine';
7 |
8 | export const player: GameObjectConfig = {
9 | zIndex: 20,
10 | sprite: ['hero', [0, 0], [32, 32], 6, [0, 1, 2]],
11 | pos: [662, 534],
12 | size: [25, 32],
13 | render: unitRender,
14 | collisions: true,
15 | parameters: {
16 | speed: 150,
17 | health: 50,
18 | spellPower: 1,
19 | level: 1,
20 | exp: 0,
21 | effects: [] as string[],
22 | currentSpell: 'fireball',
23 | direction: {},
24 | levelTable: {
25 | 1: 600,
26 | 2: 1200,
27 | 3: 2000,
28 | 4: 3000,
29 | 5: 4500,
30 | 6: 6500,
31 | 7: 9000,
32 | 8: 13000,
33 | 9: 20000,
34 | },
35 | },
36 | type: ObjectTypes.Player,
37 | conditions: [rules.selectSpellWithKeyboard],
38 | rules: [
39 | rules.moveWithKeyboard,
40 | rules.rotateToMouse,
41 | rules.bindPositionToLayer,
42 | rules.playerDeath,
43 | rules.moveToDirection,
44 | rules.dynamicZIndex,
45 | rules.resetSpeed,
46 | rules.resetEffects,
47 | rules.playerLevelUp,
48 | ],
49 | };
50 |
51 | export const summonGate: GameObjectConfig = {
52 | zIndex: 0,
53 | render: objectRender,
54 | sprite: ['arcaneGate', [0, 0], [32, 32], 7, [0, 1]],
55 | pos: [466, 580],
56 | size: [25, 30],
57 | collisions: true,
58 | parameters: {
59 | cooldown: 80,
60 | exp: 3,
61 | chanceOfBoss: 5,
62 | chanceOfBoss2: 8,
63 | chanceOfBoomer: 20,
64 | health: 10,
65 | },
66 | conditions: [rules.monsterHealthStatus],
67 | type: ObjectTypes.Monster,
68 | rules: [rules.summonOnCooldown, rules.dynamicZIndex],
69 | };
70 |
71 | export const monster: GameObjectConfig = {
72 | zIndex: 1,
73 | sprite: ['demons', [0, 128], [32, 32], 6, [0, 1, 2]],
74 | size: [20, 28],
75 | collisions: true,
76 | render: unitRender,
77 | parameters: {
78 | speed: 25,
79 | cooldown: 70,
80 | scentSpeed: 120,
81 | scentRange: 600,
82 | exp: 15,
83 | wanderCooldown: 500,
84 | effects: [] as string[],
85 | health: 20,
86 | power: 5,
87 | },
88 | conditions: [rules.monsterHealthStatus, rules.stopOnCollisionWithPlayer],
89 | type: ObjectTypes.Monster,
90 | rules: [
91 | rules.moveToDirection,
92 | rules.wandererAI,
93 | rules.rotateByDirection,
94 | rules.meleeAttack,
95 | rules.dynamicZIndex,
96 | rules.resetEffects,
97 | rules.resetMeleeCooldown,
98 | ],
99 | };
100 | export const monsterBoomer: GameObjectConfig = {
101 | zIndex: 1,
102 | sprite: ['demons', [96, 128], [32, 32], 6, [0, 1, 2]],
103 | size: [20, 28],
104 | collisions: true,
105 | render: unitRender,
106 | parameters: {
107 | speed: 100,
108 | exp: 30,
109 | effects: [] as string[],
110 | health: 10,
111 | power: 10,
112 | },
113 | conditions: [rules.monsterHealthStatus, rules.monsterExplosionCondition],
114 | type: ObjectTypes.Monster,
115 | rules: [
116 | rules.moveToDirection,
117 | rules.rotateByPlayer,
118 | rules.setDirectionToPlayerAdvance,
119 | rules.dynamicZIndex,
120 | rules.resetSpeed,
121 | rules.resetEffects,
122 | ],
123 | };
124 | export const monsterBoss: GameObjectConfig = {
125 | zIndex: 1,
126 | collisions: true,
127 | sprite: ['bigMonsters', [0, 0], [32, 50], 6, [0, 1, 2]],
128 | size: [25, 40],
129 | render: unitRender,
130 | parameters: {
131 | speed: 50,
132 | exp: 60,
133 | cooldown: 75,
134 | power: 10,
135 | health: 50,
136 | effects: [] as string[],
137 | },
138 | conditions: [rules.monsterHealthStatus, rules.stopOnCollisionWithPlayer],
139 | type: ObjectTypes.Monster,
140 | rules: [
141 | rules.setDirectionToPlayer,
142 | rules.monsterBossLogic,
143 | rules.moveToDirection,
144 | rules.rotateByDirection,
145 | rules.dynamicZIndex,
146 | rules.resetSpeed,
147 | rules.resetEffects,
148 | rules.resetRangeCooldown,
149 | ],
150 | };
151 |
152 | export const monsterBoss2: GameObjectConfig = {
153 | zIndex: 1,
154 | collisions: true,
155 | sprite: ['boss', [0, 0], [96, 48], 6, [0, 1, 2]],
156 | size: [40, 45],
157 | render: unitRender,
158 | parameters: {
159 | speed: 15,
160 | cooldown: 200,
161 | exp: 120,
162 | fireRange: 300,
163 | power: 10,
164 | health: 30,
165 | effects: [] as string[],
166 | },
167 | conditions: [rules.monsterHealthStatus, rules.stopOnCollisionWithPlayer],
168 | type: ObjectTypes.Monster,
169 | rules: [
170 | rules.setDirectionToPlayer,
171 | rules.monsterBoss2Logic,
172 | rules.rotateByDirection,
173 | rules.dynamicZIndex,
174 | rules.resetSpeed,
175 | rules.resetEffects,
176 | rules.resetRangeCooldown,
177 | ],
178 | };
179 |
180 | export const heart: GameObjectConfig = {
181 | zIndex: 3,
182 | render: objectRender,
183 | collisions: true,
184 | size: [25, 25],
185 | sprite: ['pumpkin', [0, 0], [32, 32], 5, [0, 1]],
186 | conditions: [rules.triggerOnPlayerCollision],
187 | rules: [rules.dynamicZIndex],
188 | type: ObjectTypes.PowerUp,
189 | parameters: {
190 | power: 10,
191 | },
192 | };
193 |
194 | export const powerup: GameObjectConfig = {
195 | render: spriteRender,
196 | zIndex: 2,
197 | size: [25, 25],
198 | collisions: true,
199 | sprite: ['powerUp', [0, 0], [72, 65], 15, [0, 1, 2, 1]],
200 | conditions: [rules.triggerOnPlayerCollisionPowerUp],
201 | type: ObjectTypes.PowerUp,
202 | parameters: {
203 | exp: 250,
204 | },
205 | };
206 |
--------------------------------------------------------------------------------
/src/engine/layer.ts:
--------------------------------------------------------------------------------
1 | import * as objectConfigs from "../configs/objects";
2 | import { GameObject } from "./object";
3 |
4 | import type { GameRule, GameLayerConfig, GameObjectConfig } from "./types";
5 | import type { ObjectTypes } from "../configs/objects/constants";
6 | import type { Battle } from "../states/battle";
7 |
8 | export type OBJECTS_ID = keyof typeof objectConfigs;
9 |
10 | export class GameLayer {
11 | id: string;
12 | ctx: CanvasRenderingContext2D;
13 | game: Phaser.Game;
14 | state: Battle;
15 | background: CanvasPattern;
16 | size: number[];
17 | translate: { x: number; y: number };
18 | parameters: { [key: string]: any };
19 |
20 | private inited: boolean;
21 |
22 | private config: GameLayerConfig;
23 |
24 | private objects: { [key: string]: GameObject };
25 | private sortedObjects: { [key: string]: string[] };
26 | private rules: GameRule[];
27 | private objectsToBeRemoved: string[] = [];
28 |
29 | constructor(config: GameLayerConfig) {
30 | this.config = config;
31 | this.id = config.id;
32 | this.state = config.state;
33 | this.game = this.state.game;
34 | this.ctx = config.ctx;
35 |
36 | this.background = this.ctx.createPattern(
37 | this.game.cache.getImage(config.background),
38 | "repeat"
39 | ) as CanvasPattern;
40 |
41 | this.size = config.size || [this.ctx.canvas.width, this.ctx.canvas.height];
42 |
43 | this.sortedObjects = {
44 | default: [],
45 | };
46 | this.objects = {};
47 | this.inited = false;
48 | this.parameters = {};
49 | this.rules = config.rules || [];
50 | this.translate = config.translate
51 | ? { ...config.translate }
52 | : { x: 0, y: 0 };
53 | }
54 |
55 | init() {
56 | if (!this.inited) {
57 | this.config.initList.forEach((objectID) => this.addObjectByID(objectID));
58 |
59 | this.config.init && this.config.init();
60 |
61 | this.rules.forEach((rule) => rule.init?.(this));
62 |
63 | this.inited = true;
64 | }
65 | }
66 |
67 | render(dt: number) {
68 | if (!this.inited) return;
69 |
70 | const arr: { [key: number]: GameObject[] } = {};
71 | const ctx = this.ctx;
72 |
73 | ctx.save();
74 | ctx.beginPath();
75 | ctx.rect(0, 0, this.size[0], this.size[1]);
76 | ctx.clip();
77 | ctx.translate(this.translate.x, this.translate.y);
78 | ctx.fillStyle = this.background;
79 | ctx.fillRect(0, 0, this.size[0] + 5, this.size[1] + 5);
80 |
81 | for (let i in this.objects) {
82 | if (this.objects.hasOwnProperty(i)) {
83 | arr[this.objects[i].zIndex] || (arr[this.objects[i].zIndex] = []);
84 | arr[this.objects[i].zIndex].push(this.objects[i]);
85 | }
86 | }
87 | for (let i in arr) {
88 | if (arr[i]) {
89 | for (let j = 0, k = arr[i].length; j < k; j++) {
90 | ctx.save();
91 | ctx.translate(
92 | Math.round(arr[i][j].pos.x),
93 | Math.round(arr[i][j].pos.y)
94 | );
95 |
96 | arr[i][j].render(dt);
97 |
98 | ctx.restore();
99 | }
100 | }
101 | }
102 | ctx.translate(-this.translate.x, -this.translate.y);
103 | ctx.restore();
104 | }
105 |
106 | update(dt: number) {
107 | if (!this.inited) return;
108 |
109 | for (let i in this.rules) {
110 | this.rules[i].update?.(this, dt);
111 | }
112 |
113 | for (let i in this.objects) {
114 | this.objects[i].update(dt);
115 | }
116 |
117 | for (let i in this.objects) {
118 | this.objects[i].updateCollisions();
119 | }
120 |
121 | this.state.collisions.check();
122 |
123 | for (let i in this.objects) {
124 | this.objects[i].updateConditions(dt);
125 | }
126 |
127 | while (this.objectsToBeRemoved.length) {
128 | const id = this.objectsToBeRemoved.pop();
129 | if (!id) {
130 | return;
131 | }
132 |
133 | const obj = this.objects[id];
134 | if (obj) {
135 | obj.shouldCheckCollisions && this.state.collisions.removeObject(obj!);
136 | this.removeObject(id!);
137 | }
138 | }
139 |
140 | Object.keys(this.sortedObjects).forEach((type: string) => {
141 | const sortedObjectsByType = this.sortedObjects[type];
142 | const existingObjects: string[] = [];
143 | sortedObjectsByType.forEach((id: string) => {
144 | if (this.objects[id]) {
145 | existingObjects.push(id);
146 | }
147 | });
148 | this.sortedObjects[type] = existingObjects;
149 | });
150 | }
151 |
152 | removeObjectOnNextTick(id: string) {
153 | this.objectsToBeRemoved.push(id);
154 | }
155 |
156 | addRule(rule: GameRule) {
157 | rule.init?.(this);
158 | this.rules.push(rule);
159 | }
160 |
161 | removeObject(id: string) {
162 | if (this.objects.hasOwnProperty(id)) {
163 | delete this.objects[id];
164 | }
165 | }
166 |
167 | private addObject(id: OBJECTS_ID, config: GameObjectConfig) {
168 | const obj = new GameObject({
169 | ...config,
170 | layer: this,
171 | id: `${id}-${Math.round(
172 | new Date().getTime() + Math.random() * 1000001
173 | ).toString()}`,
174 | });
175 |
176 | const type = config.type || "default";
177 |
178 | this.sortedObjects[type] = this.sortedObjects[type] || [];
179 | this.sortedObjects[type].push(obj.id);
180 |
181 | this.objects[obj.id] = obj;
182 |
183 | return this.objects[obj.id];
184 | }
185 |
186 | addObjectByID(id: OBJECTS_ID) {
187 | const config = objectConfigs[id];
188 | return this.addObject(id, config);
189 | }
190 |
191 | getObjectsByType(type: ObjectTypes) {
192 | const objectsId = this.sortedObjects[type] || [];
193 | const result: GameObject[] = [];
194 |
195 | objectsId.forEach((id) => {
196 | if (this.objects[id]) {
197 | result.push(this.objects[id]);
198 | }
199 | });
200 |
201 | return result;
202 | }
203 |
204 | getObjectByID(id: OBJECTS_ID) {
205 | return this.objects[id];
206 | }
207 |
208 | clearLayer() {
209 | this.objects = {};
210 |
211 | this.sortedObjects = {
212 | default: [],
213 | };
214 | this.parameters = {};
215 | this.inited = false;
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/src/configs/rules/etc.ts:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser';
2 |
3 | import { ObjectTypes } from '../objects/constants';
4 |
5 | import { moveWithSpeed } from './utils';
6 |
7 | import type { GameObject, GameRule } from '../../engine';
8 |
9 | export const bindPositionToLayer: GameRule = {
10 | update(obj: GameObject) {
11 | if (obj.pos.x - obj.sprite!.size[0] / 2 < 0) {
12 | obj.pos.x = obj.sprite!.size[0] / 2;
13 | } else if (obj.pos.x + obj.sprite!.size[0] / 2 > obj.layer.size[0]) {
14 | obj.pos.x = obj.layer.size[0] - obj.sprite!.size[0] / 2;
15 | }
16 |
17 | if (obj.pos.y - obj.sprite!.size[1] / 2 < 0) {
18 | obj.pos.y = obj.sprite!.size[1] / 2;
19 | } else if (obj.pos.y + obj.sprite!.size[1] / 2 > obj.layer.size[1]) {
20 | obj.pos.y = obj.layer.size[1] - obj.sprite!.size[1] / 2;
21 | }
22 | },
23 | };
24 |
25 | export const destroyAfterLeavingLayer: GameRule = {
26 | update(obj: GameObject) {
27 | if (
28 | obj.pos.y < -100 ||
29 | obj.pos.y - obj.sprite!.size[1] - 100 > obj.layer.size[1] ||
30 | obj.pos.x - obj.sprite!.size[0] - 100 > obj.layer.size[0] ||
31 | obj.pos.x < -100
32 | ) {
33 | obj.layer.removeObjectOnNextTick(obj.id);
34 | return false;
35 | }
36 | },
37 | };
38 |
39 | export const setDirectionToPlayer: GameRule = {
40 | update(obj: GameObject) {
41 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
42 |
43 | obj.parameters.direction = Phaser.Point.subtract(player.pos, obj.pos);
44 | },
45 | };
46 |
47 | export const setDirectionToPlayerAdvance: GameRule = {
48 | update(obj: GameObject) {
49 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
50 | const playerDirection: Phaser.Point | null = player.parameters.direction;
51 | const direction =
52 | obj.parameters.direction || Phaser.Point.subtract(player.pos, obj.pos);
53 |
54 | if (playerDirection == null) {
55 | obj.parameters.direction = Phaser.Point.subtract(player.pos, obj.pos);
56 | } else {
57 | const speed = Math.abs(
58 | Math.min(
59 | player.parameters.speed,
60 | Phaser.Point.distance(obj.pos, player.pos)
61 | ) - 10
62 | );
63 | const playerNextPlace = moveWithSpeed(player.pos, playerDirection, speed);
64 | const _dv = Phaser.Point.subtract(playerNextPlace, obj.pos).normalize();
65 | const _odv = direction.clone().normalize();
66 | const _ndv = Phaser.Point.add(_odv, _dv).normalize();
67 |
68 | obj.parameters.direction = _ndv;
69 | }
70 | },
71 | };
72 |
73 | export const wandererAI: GameRule = {
74 | init(obj: GameObject) {
75 | const rect = new Phaser.Rectangle(100, 100, 1000, 750);
76 | obj.parameters.direction = new Phaser.Point(rect.randomX, rect.randomY);
77 | },
78 | update(obj: GameObject) {
79 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
80 | const distance = Phaser.Point.distance(obj.pos, player.pos);
81 |
82 | if (distance <= obj.parameters.scentRange) {
83 | obj.parameters.scent = true;
84 | obj.parameters.speed = obj.defaultParameters.scentSpeed;
85 | obj.parameters.wanderCooldown = 0;
86 | obj.parameters.direction = Phaser.Point.subtract(player.pos, obj.pos);
87 | } else {
88 | obj.parameters.speed = obj.defaultParameters.speed;
89 | if (!obj.parameters.wanderCooldown) {
90 | const rect = new Phaser.Rectangle(100, 100, 1000, 750);
91 | obj.parameters.direction = Phaser.Point.subtract(
92 | new Phaser.Point(rect.randomX, rect.randomY),
93 | obj.pos
94 | );
95 | obj.parameters.wanderCooldown = Math.round(
96 | Math.random() * (obj.defaultParameters.wanderCooldown - 100) + 100
97 | );
98 | } else {
99 | obj.parameters.wanderCooldown &&
100 | (obj.parameters.wanderCooldown = obj.parameters.wanderCooldown - 1);
101 | }
102 | }
103 | },
104 | };
105 |
106 | export const dynamicZIndex: GameRule = {
107 | update(obj: GameObject) {
108 | let newZIndex = 0;
109 |
110 | obj.pos && (newZIndex += obj.pos.y);
111 | obj.sprite && (newZIndex += obj.sprite!.size[1] / 2);
112 |
113 | obj.zIndex = obj.pos.y > 0 ? Math.round(newZIndex) : 0;
114 | },
115 | };
116 |
117 |
118 | export const rotateToMouse: GameRule = {
119 | update(obj: GameObject) {
120 | const destination = new Phaser.Point(
121 | obj.layer.game.input.mousePointer.x,
122 | obj.layer.game.input.mousePointer.y
123 | );
124 |
125 | destination.x -= obj.layer.translate.x;
126 | destination.y -= obj.layer.translate.y;
127 |
128 | const directionToMouse = Phaser.Point.subtract(destination, obj.pos);
129 | obj.sprite!.rotateToDirection(directionToMouse);
130 | },
131 | };
132 |
133 | export const removeOnCooldown: GameRule = {
134 | update(obj: GameObject) {
135 | const cooldown = obj.parameters.cooldown;
136 |
137 | if (cooldown == 0) {
138 | obj.layer.removeObjectOnNextTick(obj.id);
139 | } else {
140 | obj.parameters.cooldown = cooldown - 1;
141 | }
142 | },
143 | };
144 |
145 | export const explosionOnCooldown: GameRule = {
146 | update(obj: GameObject) {
147 | const cooldown = obj.parameters.cooldown;
148 |
149 | if (cooldown == 0) {
150 | obj.layer.removeObjectOnNextTick(obj.id);
151 |
152 | const expl = obj.layer.addObjectByID('spellExplosion');
153 | expl.setPosition(new Phaser.Point(obj.pos.x, obj.pos.y));
154 | expl.parameters.power = obj.parameters.power;
155 | } else {
156 | obj.parameters.cooldown = cooldown - 1;
157 | }
158 | },
159 | };
160 |
161 | export const explosionAfterSpriteDone: GameRule = {
162 | update(obj: GameObject) {
163 | if (obj.sprite!.done) {
164 | obj.layer.removeObjectOnNextTick(obj.id);
165 |
166 | const expl = obj.layer.addObjectByID('monsterExplosion');
167 | expl.setPosition(new Phaser.Point(obj.pos.x, obj.pos.y));
168 | expl.parameters.power = obj.parameters.power;
169 | }
170 | },
171 | };
172 |
173 | export const destroyAfterSpriteDone: GameRule = {
174 | update(obj: GameObject) {
175 | if (obj.sprite!.done) {
176 | obj.layer.removeObjectOnNextTick(obj.id);
177 | }
178 | },
179 | };
180 |
181 | export const rotateByDirection: GameRule = {
182 | update(obj: GameObject) {
183 | obj.sprite!.rotateToDirection(obj.parameters.direction);
184 | },
185 | };
186 |
187 | export const rotateByPlayer: GameRule = {
188 | update(obj: GameObject) {
189 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
190 |
191 | obj.sprite!.rotateToDirection(Phaser.Point.subtract(player.pos, obj.pos));
192 | },
193 | };
194 |
--------------------------------------------------------------------------------
/src/configs/renderers.ts:
--------------------------------------------------------------------------------
1 | import { ObjectTypes } from './objects/constants';
2 | import { Effects } from './rules/constants';
3 |
4 | import type { Render } from '../engine';
5 |
6 | const ellipse = (
7 | context: CanvasRenderingContext2D,
8 | cx: number,
9 | cy: number,
10 | rx: number,
11 | ry: number,
12 | rot: number,
13 | aStart: number,
14 | aEnd: number
15 | ) => {
16 | context.save();
17 |
18 | context.translate(cx, cy);
19 | context.rotate(rot);
20 | context.translate(-rx, -ry);
21 |
22 | context.scale(rx, ry);
23 | context.arc(1, 1, 1, aStart, aEnd, false);
24 |
25 | context.restore();
26 | };
27 |
28 | export const fog: Render = (obj) => {
29 | const ctx = obj.layer.ctx;
30 | const x = obj.layer.getObjectsByType(ObjectTypes.Player)[0].pos.x;
31 | const y = obj.layer.getObjectsByType(ObjectTypes.Player)[0].pos.y;
32 | const grad = obj.layer.ctx.createRadialGradient(x, y, 0, x, y, 700);
33 |
34 | grad.addColorStop(0, 'rgba(0, 0, 0, 0)');
35 | grad.addColorStop(1, 'rgba(0, 0, 0, 0.97)');
36 | ctx.fillStyle = grad;
37 |
38 | ctx.beginPath();
39 | ctx.arc(x, y, 2000, 0, Math.PI * 2, false);
40 | ctx.closePath();
41 |
42 | ctx.fill();
43 | };
44 |
45 | export const healthBar: Render = (obj) => {
46 | const ctx = obj.layer.ctx;
47 | const x = Math.round(-obj.sprite!.size[0] / 2);
48 | const y = Math.round(-obj.sprite!.size[1] / 2 - 7);
49 | const width = obj.sprite!.size[0];
50 | const height = 3;
51 |
52 | ctx.globalAlpha = 0.5;
53 |
54 | if (
55 | obj.parameters.health > 0 &&
56 | obj.defaultParameters.health > obj.parameters.health
57 | ) {
58 | ctx.fillStyle = 'rgb(250, 0, 0)';
59 | ctx.fillRect(x, y, width, height);
60 |
61 | ctx.fillStyle = 'rgb(0, 250, 0)';
62 | ctx.fillRect(
63 | x,
64 | y,
65 | Math.round(
66 | width * (obj.parameters.health / obj.defaultParameters.health)
67 | ),
68 | height
69 | );
70 | }
71 |
72 | ctx.globalAlpha = 1;
73 | };
74 |
75 | export const expBar: Render = (obj, dt) => {
76 | const x = -22;
77 | const y = 17;
78 | const width = 200;
79 | const height = 40;
80 | const ctx = obj.layer.ctx;
81 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
82 |
83 | ctx.translate(-obj.layer.translate.x, -obj.layer.translate.y);
84 |
85 | ctx.globalAlpha = 0.3;
86 | ctx.fillStyle = 'rgb(220, 220, 220)';
87 | ctx.fillRect(x, y, width, height);
88 |
89 | ctx.globalAlpha = 1;
90 | ctx.fillStyle = '#DAA520';
91 | if (player.parameters.levelTable[player.parameters.level]) {
92 | ctx.fillRect(
93 | x,
94 | y,
95 | Math.min(
96 | width,
97 | Math.round(
98 | width *
99 | (player.parameters.exp /
100 | player.parameters.levelTable[player.parameters.level])
101 | )
102 | ),
103 | height
104 | );
105 | } else {
106 | ctx.fillRect(x, y, width, height);
107 | }
108 |
109 | ctx.translate(obj.layer.translate.x, obj.layer.translate.y);
110 |
111 | text(obj, dt);
112 | };
113 |
114 | export const sprite: Render = (obj, dt) => {
115 | const ctx = obj.layer.ctx;
116 |
117 | ctx.globalAlpha = 1;
118 | obj.sprite!.update(dt);
119 | obj.sprite!.render(ctx);
120 | };
121 |
122 | export const shadow: Render = (obj) => {
123 | if (obj.size) {
124 | const ctx = obj.layer.ctx;
125 |
126 | ctx.globalAlpha = 0.5;
127 |
128 | ctx.beginPath();
129 | ellipse(
130 | ctx,
131 | 0,
132 | +obj.sprite!.size[1] / 2 - 3,
133 | Math.min(obj.sprite!.size[0], obj.size![0]) / 2 + 8,
134 | 5,
135 | 0,
136 | 0,
137 | 2 * Math.PI
138 | );
139 | ctx.fillStyle = 'black';
140 | ctx.fill();
141 |
142 | ctx.globalAlpha = 1;
143 | }
144 | };
145 |
146 | export const effects: Render = (obj) => {
147 | const ctx = obj.layer.ctx;
148 |
149 | if (!obj.parameters.effects) {
150 | return;
151 | }
152 |
153 | Object.keys(obj.parameters.effects).forEach((effect) => {
154 | if (effect === Effects.Frozzen) {
155 | ctx.globalAlpha = 0.8;
156 | ctx.drawImage(
157 | obj.layer.game.cache.getImage('frostEffect'),
158 | -16,
159 | +(obj.sprite!.size[1] / 2) - 32,
160 | 32,
161 | 32
162 | );
163 | ctx.globalAlpha = 1;
164 | }
165 | });
166 | };
167 |
168 | export const object: Render = (obj, dt) => {
169 | shadow(obj, dt);
170 | sprite(obj, dt);
171 | };
172 |
173 | export const unit: Render = (obj, dt) => {
174 | shadow(obj, dt);
175 | healthBar(obj, dt);
176 | sprite(obj, dt);
177 | effects(obj, dt);
178 | };
179 |
180 | export const spell: Render = (obj, dt) => {
181 | const ctx = obj.layer.ctx;
182 | const x = Math.round(-obj.sprite!.size[0] / 2 - 4);
183 | const y = Math.round(-obj.sprite!.size[1] / 2 - 4);
184 | const width = obj.sprite!.size[0] + 8;
185 | const height = obj.sprite!.size[1] + 8;
186 |
187 | ctx.translate(-obj.layer.translate.x, -obj.layer.translate.y);
188 |
189 | if (
190 | obj.id.indexOf(
191 | obj.layer.getObjectsByType(ObjectTypes.Player)[0].parameters.currentSpell
192 | ) !== -1
193 | ) {
194 | ctx.fillStyle = 'rgb(0, 250, 0)';
195 | ctx.fillRect(x - 2, y - 2, width + 4, height + 4);
196 | }
197 |
198 | ctx.globalAlpha = 0.4;
199 | ctx.fillStyle = 'rgb(0, 0, 0)';
200 |
201 | ctx.fillRect(x, y, width, height);
202 |
203 | ctx.fillStyle = 'rgb(0, 0, 0)';
204 | ctx.fillRect(x, y, width, height);
205 |
206 | ctx.globalAlpha = 1;
207 |
208 | sprite(obj, dt);
209 |
210 | if (obj.parameters.fireCooldown > 0) {
211 | ctx.globalAlpha = 0.8;
212 | ctx.fillStyle = 'rgb(20, 20, 20)';
213 | ctx.fillRect(
214 | x,
215 | Math.round(
216 | y +
217 | height -
218 | height * (obj.parameters.fireCooldown / obj.parameters.cooldown)
219 | ),
220 | width,
221 | height
222 | );
223 | ctx.globalAlpha = 1;
224 | }
225 |
226 | ctx.translate(obj.layer.translate.x, obj.layer.translate.y);
227 | };
228 |
229 | export const ui: Render = (obj, dt) => {
230 | const ctx = obj.layer.ctx;
231 |
232 | ctx.translate(-obj.layer.translate.x, -obj.layer.translate.y);
233 | sprite(obj, dt);
234 | ctx.translate(obj.layer.translate.x, obj.layer.translate.y);
235 | };
236 |
237 | export const text: Render = (obj) => {
238 | const ctx = obj.layer.ctx;
239 | let fontConfig = '';
240 |
241 | ctx.translate(-obj.layer.translate.x, -obj.layer.translate.y);
242 |
243 | obj.parameters.style && (fontConfig += obj.parameters.style + ' ');
244 | obj.parameters.weight && (fontConfig += obj.parameters.weight + ' ');
245 |
246 | fontConfig += (obj.parameters.size || 30) + 'pt ';
247 | fontConfig += obj.parameters.font || 'Arial';
248 |
249 | if (obj.parameters.align) {
250 | ctx.textAlign = obj.parameters.align;
251 | }
252 |
253 | ctx.font = fontConfig;
254 | ctx.fillStyle = obj.parameters.color || '#FFF';
255 | ctx.fillText(obj.parameters.text, obj.pos.x, obj.pos.y);
256 |
257 | ctx.translate(obj.layer.translate.x, obj.layer.translate.y);
258 | };
--------------------------------------------------------------------------------
/src/configs/rules/spells.ts:
--------------------------------------------------------------------------------
1 | import Phaser, { Point } from 'phaser';
2 |
3 | import { ObjectTypes } from '../objects/constants';
4 | import { moveWithSpeed } from './utils';
5 | import { Effects } from './constants';
6 |
7 | import type { GameObject, GameRule } from '../../engine';
8 |
9 | export const fireball: GameRule = {
10 | update(obj: GameObject) {
11 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
12 | const fireCooldown = obj.parameters.fireCooldown;
13 | const spellPower = player.parameters.spellPower;
14 |
15 | const createBullet = (direction: Point, destination: Point) => {
16 | const bull = obj.layer.addObjectByID('bullet');
17 | bull.setPosition(player.pos.clone());
18 | bull.parameters.direction = direction;
19 | bull.parameters.power = bull.parameters.power + 5 * (spellPower - 1);
20 | bull.sprite!.setDegree(player.pos.angle(destination));
21 | };
22 |
23 | if (player.parameters.currentSpell == 'fireball') {
24 | if (
25 | obj.layer.game.input.mousePointer.isDown ||
26 | obj.layer.game.input.keyboard.isDown(32)
27 | ) {
28 | if (!fireCooldown) {
29 | const destination = new Phaser.Point(
30 | obj.layer.game.input.mousePointer.x,
31 | obj.layer.game.input.mousePointer.y
32 | );
33 | let startDegree = 10 * (spellPower - 1);
34 |
35 | destination.x -= obj.layer.translate.x;
36 | destination.y -= obj.layer.translate.y;
37 |
38 | for (let i = 0; i < spellPower; i++) {
39 | const movedPoint = destination
40 | .clone()
41 | .rotate(player.pos.x, player.pos.y, startDegree, true);
42 |
43 | createBullet(
44 | Phaser.Point.subtract(movedPoint, player.pos),
45 | movedPoint.clone()
46 | );
47 |
48 | startDegree -= 20;
49 | }
50 | obj.parameters.cooldown = obj.defaultParameters.cooldown;
51 | obj.parameters.fireCooldown = obj.parameters.cooldown;
52 | }
53 | }
54 | }
55 | fireCooldown && (obj.parameters.fireCooldown = fireCooldown - 1);
56 | },
57 | };
58 |
59 | export const hellfire: GameRule = {
60 | update(obj: GameObject) {
61 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
62 | const fireCooldown = obj.parameters.fireCooldown;
63 |
64 | const createTube = (pos: Phaser.Point) => {
65 | const spellPower = player.parameters.spellPower;
66 |
67 | const tube = obj.layer.addObjectByID('hellfireTube');
68 | tube.setPosition(pos);
69 | tube.parameters.power = tube.parameters.power + 5 * (spellPower - 1);
70 | };
71 |
72 | if (player.parameters.currentSpell == 'hellfire') {
73 | if (
74 | obj.layer.game.input.mousePointer.isDown ||
75 | obj.layer.game.input.keyboard.isDown(32)
76 | ) {
77 | if (!fireCooldown) {
78 | const destination = new Phaser.Point(0, 1),
79 | point1 = moveWithSpeed(player.pos, destination, 100);
80 |
81 | for (let i = -10; i < 10; i++) {
82 | const movedPoint = point1
83 | .clone()
84 | .rotate(player.pos.x, player.pos.y, 18 * i, true);
85 |
86 | createTube(movedPoint);
87 | }
88 |
89 | obj.parameters.cooldown = obj.defaultParameters.cooldown;
90 | obj.parameters.fireCooldown = obj.parameters.cooldown;
91 | }
92 | }
93 | }
94 | fireCooldown && (obj.parameters.fireCooldown = fireCooldown - 1);
95 | },
96 | };
97 |
98 | export const slowEnemies: GameRule = {
99 | update(obj: GameObject) {
100 | const { objects } = obj.collisions;
101 |
102 | for (let i = 0; i < objects.length; i++) {
103 | if (objects[i].type == 'monster') {
104 | const speed = objects[i].parameters.speed;
105 | const power = obj.parameters.power;
106 | const effects = objects[i].parameters.effects || {};
107 |
108 | if (speed < power) {
109 | objects[i].parameters.speed = 0;
110 | } else {
111 | objects[i].parameters.speed = speed - power;
112 | }
113 |
114 | effects[Effects.Frozzen] = true;
115 | }
116 | }
117 | },
118 | };
119 | export const teleport: GameRule = {
120 | update(obj: GameObject) {
121 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
122 | const fireCooldown = obj.parameters.fireCooldown;
123 |
124 | if (player.parameters.currentSpell == 'teleport') {
125 | if (
126 | obj.layer.game.input.mousePointer.isDown ||
127 | obj.layer.game.input.keyboard.isDown(32)
128 | ) {
129 | if (!fireCooldown) {
130 | const mouse = new Phaser.Point(
131 | obj.layer.game.input.mousePointer.x,
132 | obj.layer.game.input.mousePointer.y
133 | );
134 |
135 | mouse.x -= obj.layer.translate.x;
136 | mouse.y -= obj.layer.translate.y;
137 |
138 | const direction = Phaser.Point.subtract(mouse, player.pos);
139 | const spellPower = player.parameters.spellPower;
140 | const destination = moveWithSpeed(
141 | player.pos,
142 | direction,
143 | obj.parameters.power
144 | );
145 | const cooldown: number =
146 | obj.defaultParameters.cooldown - 30 * (spellPower - 1);
147 |
148 | const starTeleportGate = obj.layer.addObjectByID('teleportGate');
149 | starTeleportGate.setPosition(player.pos.clone());
150 |
151 | const endTeleportGate = obj.layer.addObjectByID('teleportGate');
152 | endTeleportGate.setPosition(destination.clone());
153 |
154 | player.setPosition(destination);
155 |
156 | obj.parameters.cooldown = cooldown > 50 ? cooldown : 50;
157 | obj.parameters.fireCooldown = obj.parameters.cooldown;
158 | }
159 | }
160 | }
161 | fireCooldown && (obj.parameters.fireCooldown = fireCooldown - 1);
162 | },
163 | };
164 |
165 | export const frostShard: GameRule = {
166 | update(obj: GameObject) {
167 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
168 | const fireCooldown = obj.parameters.fireCooldown;
169 |
170 | if (player.parameters.currentSpell == 'frostShard') {
171 | if (
172 | obj.layer.game.input.mousePointer.isDown ||
173 | obj.layer.game.input.keyboard.isDown(32)
174 | ) {
175 | if (!fireCooldown) {
176 | const mousePosition = new Phaser.Point(
177 | obj.layer.game.input.mousePointer.x,
178 | obj.layer.game.input.mousePointer.y
179 | );
180 | const spellPower = player.parameters.spellPower;
181 | const destination = mousePosition.clone();
182 |
183 | destination.x -= obj.layer.translate.x;
184 | destination.y -= obj.layer.translate.y;
185 |
186 | let spellPowerBoost = 0;
187 |
188 | for (let i = 1; i < spellPower; i++) {
189 | spellPowerBoost += 50;
190 | }
191 |
192 | const fs = obj.layer.addObjectByID('frostShard');
193 | fs.setPosition(destination.clone());
194 |
195 | fs.parameters.cooldown = fs.parameters.cooldown + spellPowerBoost;
196 |
197 | obj.parameters.fireCooldown = obj.parameters.cooldown;
198 | }
199 | }
200 | }
201 | fireCooldown && (obj.parameters.fireCooldown = fireCooldown - 1);
202 | },
203 | };
204 |
205 | export const bulletMonsterCollision: GameRule = {
206 | update(obj: GameObject) {
207 | const { objects } = obj.collisions;
208 |
209 | for (let i = 0, l = objects.length; i < l; i++) {
210 | if (objects[i].type == 'monster') {
211 | objects[i].parameters.health =
212 | objects[i].parameters.health - obj.parameters.power;
213 |
214 | const pos = objects[i].pos.clone();
215 | pos.x += 2;
216 | pos.y += -10;
217 |
218 | const blood = obj.layer.addObjectByID('bloodSpray');
219 | blood.setPosition(pos);
220 |
221 | obj.layer.removeObjectOnNextTick(obj.id);
222 |
223 | break;
224 | }
225 | }
226 | },
227 | };
228 |
229 | export const hellTubeMonsterCollision: GameRule = {
230 | update(obj: GameObject) {
231 | const { objects } = obj.collisions;
232 |
233 | for (let i = 0, l = objects.length; i < l; i++) {
234 | if (objects[i].type == 'monster') {
235 | objects[i].parameters.health =
236 | objects[i].parameters.health - obj.parameters.power;
237 |
238 | const pos = objects[i].pos.clone();
239 | pos.x += 2;
240 | pos.y += -10;
241 |
242 | const blood = obj.layer.addObjectByID('bloodSpray');
243 | blood.setPosition(pos);
244 | }
245 | }
246 | },
247 | };
248 |
--------------------------------------------------------------------------------
/src/configs/rules/units.ts:
--------------------------------------------------------------------------------
1 | import Phaser from 'phaser';
2 |
3 | import { moveWithSpeed } from './utils';
4 |
5 | import { ObjectTypes } from '../objects/constants';
6 |
7 | import type { GameObject, GameRule } from '../../engine';
8 |
9 | export const playerDeath: GameRule = {
10 | update(obj: GameObject) {
11 | if (obj.parameters.health <= 0) {
12 | obj.layer.state.stopBattle();
13 | }
14 | },
15 | };
16 |
17 | export const damageOnPlayerCollision: GameRule = {
18 | update(obj: GameObject) {
19 | const { objects } = obj.collisions;
20 |
21 | for (let i = 0; i < objects.length; i++) {
22 | if (objects[i].type == 'player') {
23 | objects[i].parameters.health =
24 | objects[i].parameters.health - obj.parameters.power;
25 | break;
26 | }
27 | }
28 | },
29 | };
30 |
31 | export const destroyOnPlayerCollision: GameRule = {
32 | update(obj: GameObject) {
33 | const { objects } = obj.collisions;
34 |
35 | for (let i = 0; i < objects.length; i++) {
36 | if (objects[i].type == 'player') {
37 | const expl = obj.layer.addObjectByID('explosion');
38 | expl.setPosition(obj.pos.clone());
39 |
40 | obj.layer.removeObjectOnNextTick(obj.id);
41 | break;
42 | }
43 | }
44 | },
45 | };
46 |
47 | export const triggerOnPlayerCollision: GameRule = {
48 | update(obj: GameObject) {
49 | const { objects } = obj.collisions;
50 |
51 | for (let i = 0; i < objects.length; i++) {
52 | if (objects[i].type == 'player') {
53 | if (
54 | objects[i].parameters.health < objects[i].defaultParameters.health
55 | ) {
56 | if (
57 | objects[i].parameters.health + obj.parameters.power <=
58 | objects[i].defaultParameters.health
59 | ) {
60 | objects[i].parameters.health =
61 | objects[i].parameters.health + obj.parameters.power;
62 | } else {
63 | objects[i].parameters.health = objects[i].defaultParameters.health;
64 | }
65 | }
66 |
67 | obj.layer.removeObjectOnNextTick(obj.id);
68 | break;
69 | }
70 | }
71 | },
72 | };
73 |
74 | export const meleeAttack: GameRule = {
75 | update(obj: GameObject) {
76 | if (!obj.parameters.meleeCooldown) {
77 | const { objects } = obj.collisions;
78 |
79 | for (let i = 0; i < objects.length; i++) {
80 | if (objects[i].type == 'player') {
81 | objects[i].parameters.health =
82 | objects[i].parameters.health - obj.parameters.power;
83 |
84 | const pos = objects[i].pos.clone();
85 | pos.x += 2;
86 | pos.y += -10;
87 | const blood = obj.layer.addObjectByID('bloodSpray');
88 | blood.setPosition(pos);
89 |
90 | obj.parameters.meleeCooldown = obj.parameters.cooldown;
91 | break;
92 | }
93 | }
94 | }
95 | },
96 | };
97 |
98 | export const spellExplosion: GameRule = {
99 | update(obj: GameObject) {
100 | if (!obj.parameters.exploded) {
101 | const { objects } = obj.collisions;
102 |
103 | for (let i = 0, l = objects.length; i < l; i++) {
104 | if (objects[i].parameters.health && objects[i].type !== 'player') {
105 | objects[i].parameters.health =
106 | objects[i].parameters.health - obj.parameters.power;
107 | break;
108 | }
109 | }
110 |
111 | obj.parameters.exploded = true;
112 | }
113 | },
114 | };
115 |
116 | export const monsterExplosion: GameRule = {
117 | update(obj: GameObject) {
118 | if (!obj.parameters.exploded) {
119 | const { objects } = obj.collisions;
120 |
121 | for (let i = 0, l = objects.length; i < l; i++) {
122 | if (objects[i].parameters.health) {
123 | objects[i].parameters.health =
124 | objects[i].parameters.health - obj.parameters.power;
125 | break;
126 | }
127 | }
128 |
129 | obj.parameters.exploded = true;
130 | }
131 | },
132 | };
133 |
134 | const generateExplosions = (obj: GameObject) => {
135 | const pos = obj.pos.clone();
136 | const power = obj.parameters.power;
137 | let expl;
138 |
139 | obj.layer.removeObjectOnNextTick(obj.id);
140 |
141 | expl = obj.layer.addObjectByID('monsterExplosion');
142 | expl.setPosition(
143 | new Phaser.Point(pos.x - obj.size![0], pos.y - obj.size![1])
144 | );
145 | expl.parameters.power = power;
146 |
147 | expl = obj.layer.addObjectByID('monsterExplosion');
148 | expl.setPosition(
149 | new Phaser.Point(pos.x + obj.size![0], pos.y - obj.size![1])
150 | );
151 | expl.parameters.power = power;
152 |
153 | expl = obj.layer.addObjectByID('monsterExplosion');
154 | expl.setPosition(
155 | new Phaser.Point(pos.x - obj.size![0], pos.y + obj.size![1])
156 | );
157 | expl.parameters.power = power;
158 |
159 | expl = obj.layer.addObjectByID('monsterExplosion');
160 | expl.setPosition(
161 | new Phaser.Point(pos.x + obj.size![0], pos.y + obj.size![1])
162 | );
163 | expl.parameters.power = power;
164 |
165 | expl = obj.layer.addObjectByID('monsterExplosion');
166 | expl.setPosition(new Phaser.Point(pos.x - (3 / 2) * obj.size![0], pos.y));
167 | expl.parameters.power = power;
168 |
169 | expl = obj.layer.addObjectByID('monsterExplosion');
170 | expl.setPosition(new Phaser.Point(pos.x + (3 / 2) * obj.size![0], pos.y));
171 | expl.parameters.power = power;
172 | };
173 |
174 | export const monsterExplosionCondition: GameRule = {
175 | update(obj: GameObject) {
176 | if (obj.parameters.health <= 0) {
177 | generateExplosions(obj);
178 | } else {
179 | const { objects } = obj.collisions;
180 |
181 | for (let i = 0; i < objects.length; i++) {
182 | if (objects[i].type == 'player') {
183 | generateExplosions(obj);
184 |
185 | break;
186 | }
187 | }
188 | }
189 | },
190 | };
191 |
192 | export const stopOnCollisionWithPlayer: GameRule = {
193 | update(obj: GameObject) {
194 | const { objects } = obj.collisions;
195 |
196 | for (let i = 0, l = objects.length; i < l; i++) {
197 | if (objects[i].type == 'player') {
198 | obj.parameters.speed = 0;
199 | break;
200 | }
201 | }
202 | },
203 | };
204 |
205 | export const resetSpeed: GameRule = {
206 | update(obj: GameObject) {
207 | obj.parameters.speed = obj.defaultParameters.speed;
208 | },
209 | };
210 |
211 | export const resetEffects: GameRule = {
212 | update(obj: GameObject) {
213 | obj.parameters.effects = {};
214 | },
215 | };
216 |
217 | export const moveToDirection: GameRule = {
218 | update(obj: GameObject, dt: number) {
219 | const direction = obj.parameters.direction;
220 |
221 | if (direction) {
222 | obj.setPosition(
223 | moveWithSpeed(obj.pos, direction, obj.parameters.speed * dt)
224 | );
225 | }
226 | },
227 | };
228 |
229 | export const playerLevelUp: GameRule = {
230 | update(obj: GameObject) {
231 | const levelExp = obj.parameters.levelTable[obj.parameters.level];
232 |
233 | if (obj.parameters.levelTable[obj.parameters.level]) {
234 | if (
235 | obj.parameters.exp > obj.parameters.levelTable[obj.parameters.level]
236 | ) {
237 | obj.parameters.exp = obj.parameters.exp - levelExp;
238 | obj.parameters.level = obj.parameters.level + 1;
239 | obj.parameters.spellPower = obj.parameters.spellPower + 1;
240 | }
241 | } else {
242 | obj.parameters.level = 'MAX';
243 | }
244 | },
245 | };
246 |
247 | export const monsterHealthStatus: GameRule = {
248 | update(obj: GameObject) {
249 | if (obj.parameters.health <= 0) {
250 | obj.layer.removeObjectOnNextTick(obj.id);
251 |
252 | const expl = obj.layer.addObjectByID('explosion');
253 | expl.setPosition(obj.pos.clone());
254 |
255 | const blood = obj.layer.addObjectByID('blood');
256 | blood.setPosition(obj.pos.clone());
257 |
258 | if (!obj.layer.state.parameters.monstersKilled) {
259 | obj.layer.state.parameters.monstersKilled = 0;
260 | }
261 |
262 | const monsterController = obj.layer.getObjectsByType(
263 | ObjectTypes.Controller
264 | )[0];
265 | monsterController.parameters.monsterKilled =
266 | monsterController.parameters.monsterKilled + 1;
267 |
268 | obj.layer.state.parameters.monstersKilled++;
269 |
270 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
271 | player.parameters.exp = player.parameters.exp + obj.parameters.exp;
272 | }
273 | },
274 | };
275 |
276 | export const resetRangeCooldown: GameRule = {
277 | update(obj: GameObject) {
278 | const fireCooldown = obj.parameters.fireCooldown;
279 |
280 | fireCooldown && (obj.parameters.fireCooldown = fireCooldown - 1);
281 | },
282 | };
283 |
284 | export const resetMeleeCooldown: GameRule = {
285 | update(obj: GameObject) {
286 | const meleeCooldown = obj.parameters.meleeCooldown;
287 |
288 | meleeCooldown && (obj.parameters.meleeCooldown = meleeCooldown - 1);
289 | },
290 | };
291 |
292 | export const monsterBossLogic: GameRule = {
293 | update(obj: GameObject) {
294 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
295 |
296 | if (!obj.parameters.fireCooldown) {
297 | const direction = Phaser.Point.subtract(player.pos, obj.pos);
298 |
299 | const bull = obj.layer.addObjectByID('mbullet');
300 | bull.setPosition(obj.pos.clone());
301 | bull.parameters.direction = direction;
302 |
303 | bull.sprite!.setDegree(obj.pos.angle(player.pos));
304 |
305 | obj.parameters.fireCooldown = obj.parameters.cooldown;
306 | }
307 | },
308 | };
309 |
310 | export const monsterBoss2Logic: GameRule = {
311 | update(obj: GameObject, dt: number) {
312 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
313 | const directionToPlayer = obj.parameters.direction;
314 |
315 | if (Phaser.Point.distance(obj.pos, player.pos) < obj.parameters.fireRange) {
316 | if (!obj.parameters.fireCooldown) {
317 | const bull = obj.layer.addObjectByID('mbullet2');
318 | bull.setPosition(obj.pos.clone());
319 | bull.parameters.direction = directionToPlayer;
320 |
321 | obj.parameters.fireCooldown = obj.parameters.cooldown;
322 | }
323 | } else {
324 | obj.setPosition(
325 | moveWithSpeed(obj.pos, directionToPlayer, obj.parameters.speed * dt)
326 | );
327 | }
328 | },
329 | };
330 |
331 | const createExplosion = (obj: GameObject) => {
332 | const pos = obj.pos.clone();
333 | const power = obj.parameters.power;
334 |
335 | const expl = obj.layer.addObjectByID('monsterExplosion');
336 | expl.setPosition(pos);
337 | expl.parameters.power = power;
338 | };
339 |
340 | export const monsterBoss2Bullet: GameRule = {
341 | update(obj: GameObject) {
342 | const cooldown = obj.parameters.cooldown;
343 | const { objects } = obj.collisions;
344 |
345 | if (cooldown == 0) {
346 | obj.layer.removeObjectOnNextTick(obj.id);
347 |
348 | createExplosion(obj);
349 | return;
350 | } else {
351 | obj.parameters.cooldown = cooldown - 1;
352 | }
353 |
354 | for (let i = 0; i < objects.length; i++) {
355 | if (objects[i].type == 'player') {
356 | obj.layer.removeObjectOnNextTick(obj.id);
357 |
358 | createExplosion(obj);
359 | break;
360 | }
361 | }
362 | },
363 | };
364 |
365 | export const moveWithKeyboard: GameRule = {
366 | update(obj: GameObject) {
367 | const pos = obj.pos.clone();
368 |
369 | if (obj.layer.game.input.keyboard.isDown(68)) {
370 | pos.x = obj.pos.x + 1;
371 | }
372 | if (obj.layer.game.input.keyboard.isDown(65)) {
373 | pos.x = obj.pos.x - 1;
374 | }
375 | if (obj.layer.game.input.keyboard.isDown(83)) {
376 | pos.y = obj.pos.y + 1;
377 | }
378 | if (obj.layer.game.input.keyboard.isDown(87)) {
379 | pos.y = obj.pos.y - 1;
380 | }
381 |
382 | if (obj.pos.x == pos.x && obj.pos.y == pos.y) {
383 | obj.parameters.direction = null;
384 | } else {
385 | obj.parameters.direction = Phaser.Point.subtract(pos, obj.pos);
386 | }
387 | },
388 | };
389 |
390 | export const selectSpellWithKeyboard: GameRule = {
391 | update(obj: GameObject) {
392 | obj.layer.game.input.keyboard.isDown(49) &&
393 | (obj.parameters.currentSpell = 'fireball');
394 | obj.layer.game.input.keyboard.isDown(50) &&
395 | (obj.parameters.currentSpell = 'hellfire');
396 | obj.layer.game.input.keyboard.isDown(51) &&
397 | (obj.parameters.currentSpell = 'frostShard');
398 | obj.layer.game.input.keyboard.isDown(52) &&
399 | (obj.parameters.currentSpell = 'teleport');
400 | },
401 | };
402 |
403 | export const triggerOnPlayerCollisionPowerUp: GameRule = {
404 | update(obj: GameObject) {
405 | const { objects } = obj.collisions;
406 |
407 | for (let i = 0; i < objects.length; i++) {
408 | if (objects[i].type == 'player') {
409 | //objects[i].parameters.spellPower', objects[i].parameters.spellPower') + obj.parameters.power'));
410 | objects[i].parameters.exp =
411 | objects[i].parameters.exp + obj.parameters.exp;
412 | obj.layer.removeObjectOnNextTick(obj.id);
413 | break;
414 | }
415 | }
416 | },
417 | };
418 |
419 | export const summonOnCooldown: GameRule = {
420 | update(obj: GameObject) {
421 | const cooldown = obj.parameters.cooldown;
422 |
423 | const getProperMonster = () => {
424 | let random = Math.random() * 100;
425 |
426 | if (random <= obj.parameters.chanceOfBoss) {
427 | return 'monsterBoss';
428 | } else {
429 | random -= obj.parameters.chanceOfBoss;
430 | }
431 |
432 | if (random <= obj.parameters.chanceOfBoss2) {
433 | return 'monsterBoss2';
434 | } else {
435 | random -= obj.parameters.chanceOfBoss2;
436 | }
437 |
438 | if (random <= obj.parameters.chanceOfBoomer) {
439 | return 'monsterBoomer';
440 | } else {
441 | random -= obj.parameters.monsterBoomer;
442 | }
443 |
444 | return 'monster';
445 | };
446 |
447 | if (cooldown == 0) {
448 | const player = obj.layer.getObjectsByType(ObjectTypes.Player)[0];
449 |
450 | const monster = obj.layer.addObjectByID(getProperMonster());
451 | monster.setPosition(obj.pos.clone());
452 |
453 | if (player.parameters.level > 1) {
454 | monster.parameters.health =
455 | monster.parameters.health * 0.75 * player.parameters.level;
456 | }
457 |
458 | obj.layer.removeObjectOnNextTick(obj.id);
459 | } else {
460 | obj.parameters.cooldown = cooldown - 1;
461 | }
462 | },
463 | };
464 |
--------------------------------------------------------------------------------
/src/types/p2.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for p2.js v0.6.0
2 | // Project: https://github.com/schteppe/p2.js/
3 |
4 | declare module p2 {
5 |
6 | export class AABB {
7 |
8 | constructor(options?: {
9 | upperBound?: number[];
10 | lowerBound?: number[];
11 | });
12 |
13 | setFromPoints(points: number[][], position: number[], angle: number, skinSize: number): void;
14 | copy(aabb: AABB): void;
15 | extend(aabb: AABB): void;
16 | overlaps(aabb: AABB): boolean;
17 |
18 | }
19 |
20 | export class Broadphase {
21 |
22 | static AABB: number;
23 | static BOUNDING_CIRCLE: number;
24 |
25 | static NAIVE: number;
26 | static SAP: number;
27 |
28 | static boundingRadiusCheck(bodyA: Body, bodyB: Body): boolean;
29 | static aabbCheck(bodyA: Body, bodyB: Body): boolean;
30 | static canCollide(bodyA: Body, bodyB: Body): boolean;
31 |
32 | constructor(type: number);
33 |
34 | type: number;
35 | result: Body[];
36 | world: World;
37 | boundingVolumeType: number;
38 |
39 | setWorld(world: World): void;
40 | getCollisionPairs(world: World): Body[];
41 | boundingVolumeCheck(bodyA: Body, bodyB: Body): boolean;
42 |
43 | }
44 |
45 | export class GridBroadphase extends Broadphase {
46 |
47 | constructor(options?: {
48 | xmin?: number;
49 | xmax?: number;
50 | ymin?: number;
51 | ymax?: number;
52 | nx?: number;
53 | ny?: number;
54 | });
55 |
56 | xmin: number;
57 | xmax: number;
58 | ymin: number;
59 | ymax: number;
60 | nx: number;
61 | ny: number;
62 | binsizeX: number;
63 | binsizeY: number;
64 |
65 | }
66 |
67 | export class NativeBroadphase extends Broadphase {
68 |
69 | }
70 |
71 | export class Narrowphase {
72 |
73 | contactEquations: ContactEquation[];
74 | frictionEquations: FrictionEquation[];
75 | enableFriction: boolean;
76 | slipForce: number;
77 | frictionCoefficient: number;
78 | surfaceVelocity: number;
79 | reuseObjects: boolean;
80 | resuableContactEquations: any[];
81 | reusableFrictionEquations: any[];
82 | restitution: number;
83 | stiffness: number;
84 | relaxation: number;
85 | frictionStiffness: number;
86 | frictionRelaxation: number;
87 | enableFrictionReduction: boolean;
88 | contactSkinSize: number;
89 |
90 | collidedLastStep(bodyA: Body, bodyB: Body): boolean;
91 | reset(): void;
92 | createContactEquation(bodyA: Body, bodyB: Body, shapeA: Shape, shapeB: Shape): ContactEquation;
93 | createFrictionFromContact(c: ContactEquation): FrictionEquation;
94 |
95 | }
96 |
97 | export class SAPBroadphase extends Broadphase {
98 |
99 | axisList: Body[];
100 | axisIndex: number;
101 |
102 | }
103 |
104 | export class Constraint {
105 |
106 | static DISTANCE: number;
107 | static GEAR: number;
108 | static LOCK: number;
109 | static PRISMATIC: number;
110 | static REVOLUTE: number;
111 |
112 | constructor(bodyA: Body, bodyB: Body, type: number, options?: {
113 | collideConnected?: boolean;
114 | wakeUpBodies?: boolean;
115 | });
116 |
117 | type: number;
118 | equeations: Equation[];
119 | bodyA: Body;
120 | bodyB: Body;
121 | collideConnected: boolean;
122 |
123 | update(): void;
124 | setStiffness(stiffness: number): void;
125 | setRelaxation(relaxation: number): void;
126 |
127 | }
128 |
129 | export class DistanceConstraint extends Constraint {
130 |
131 | constructor(bodyA: Body, bodyB: Body, type: number, options?: {
132 | collideConnected?: boolean;
133 | wakeUpBodies?: boolean;
134 | distance?: number;
135 | localAnchorA?: number[];
136 | localAnchorB?: number[];
137 | maxForce?: number;
138 | });
139 |
140 | localAnchorA: number[];
141 | localAnchorB: number[];
142 | distance: number;
143 | maxForce: number;
144 | upperLimitEnabled: boolean;
145 | upperLimit: number;
146 | lowerLimitEnabled: boolean;
147 | lowerLimit: number;
148 | position: number;
149 |
150 | setMaxForce(f: number): void;
151 | getMaxForce(): number;
152 |
153 | }
154 |
155 | export class GearConstraint extends Constraint {
156 |
157 | constructor(bodyA: Body, bodyB: Body, type: number, options?: {
158 | collideConnected?: boolean;
159 | wakeUpBodies?: boolean;
160 | angle?: number;
161 | ratio?: number;
162 | maxTorque?: number;
163 | });
164 |
165 | ratio: number;
166 | angle: number;
167 |
168 | setMaxTorque(torque: number): void;
169 | getMaxTorque(): number;
170 |
171 | }
172 |
173 | export class LockConstraint extends Constraint {
174 |
175 | constructor(bodyA: Body, bodyB: Body, type: number, options?: {
176 | collideConnected?: boolean;
177 | wakeUpBodies?: boolean;
178 | localOffsetB?: number[];
179 | localAngleB?: number;
180 | maxForce?: number;
181 | });
182 |
183 | setMaxForce(force: number): void;
184 | getMaxForce(): number;
185 |
186 | }
187 |
188 | export class PrismaticConstraint extends Constraint {
189 |
190 | constructor(bodyA: Body, bodyB: Body, type: number, options?: {
191 | collideConnected?: boolean;
192 | wakeUpBodies?: boolean;
193 | maxForce?: number;
194 | localAnchorA?: number[];
195 | localAnchorB?: number[];
196 | localAxisA?: number[];
197 | disableRotationalLock?: boolean;
198 | upperLimit?: number;
199 | lowerLimit?: number;
200 | });
201 |
202 | localAnchorA: number[];
203 | localAnchorB: number[];
204 | localAxisA: number[];
205 | position: number;
206 | velocity: number;
207 | lowerLimitEnabled: boolean;
208 | upperLimitEnabled: boolean;
209 | lowerLimit: number;
210 | upperLimit: number;
211 | upperLimitEquation: ContactEquation;
212 | lowerLimitEquation: ContactEquation;
213 | motorEquation: Equation;
214 | motorEnabled: boolean;
215 | motorSpeed: number;
216 |
217 | enableMotor(): void;
218 | disableMotor(): void;
219 | setLimits(lower: number, upper: number): void;
220 |
221 | }
222 |
223 | export class RevoluteConstraint extends Constraint {
224 |
225 | constructor(bodyA: Body, bodyB: Body, type: number, options?: {
226 | collideConnected?: boolean;
227 | wakeUpBodies?: boolean;
228 | worldPivot?: number[];
229 | localPivotA?: number[];
230 | localPivotB?: number[];
231 | maxForce?: number;
232 | });
233 |
234 | pivotA: number[];
235 | pivotB: number[];
236 | motorEquation: RotationalVelocityEquation;
237 | motorEnabled: boolean;
238 | angle: number;
239 | lowerLimitEnabled: boolean;
240 | upperLimitEnabled: boolean;
241 | lowerLimit: number;
242 | upperLimit: number;
243 | upperLimitEquation: ContactEquation;
244 | lowerLimitEquation: ContactEquation;
245 |
246 | enableMotor(): void;
247 | disableMotor(): void;
248 | motorIsEnabled(): boolean;
249 | setLimits(lower: number, upper: number): void;
250 | setMotorSpeed(speed: number): void;
251 | getMotorSpeed(): number;
252 |
253 | }
254 |
255 | export class AngleLockEquation extends Equation {
256 |
257 | constructor(bodyA: Body, bodyB: Body, options?: {
258 | angle?: number;
259 | ratio?: number;
260 | });
261 |
262 | computeGq(): number;
263 | setRatio(ratio: number): number;
264 | setMaxTorque(torque: number): number;
265 |
266 | }
267 |
268 | export class ContactEquation extends Equation {
269 |
270 | constructor(bodyA: Body, bodyB: Body);
271 |
272 | contactPointA: number[];
273 | penetrationVec: number[];
274 | contactPointB: number[];
275 | normalA: number[];
276 | restitution: number;
277 | firstImpact: boolean;
278 | shapeA: Shape;
279 | shapeB: Shape;
280 |
281 | computeB(a: number, b: number, h: number): number;
282 |
283 | }
284 |
285 | export class Equation {
286 |
287 | static DEFAULT_STIFFNESS: number;
288 | static DEFAULT_RELAXATION: number;
289 |
290 | constructor(bodyA: Body, bodyB: Body, minForce?: number, maxForce?: number);
291 |
292 | minForce: number;
293 | maxForce: number;
294 | bodyA: Body;
295 | bodyB: Body;
296 | stiffness: number;
297 | relaxation: number;
298 | G: number[];
299 | offset: number;
300 | a: number;
301 | b: number;
302 | epsilon: number;
303 | timeStep: number;
304 | needsUpdate: boolean;
305 | multiplier: number;
306 | relativeVelocity: number;
307 | enabled: boolean;
308 |
309 | gmult(G: number[], vi: number[], wi: number[], vj: number[], wj: number[]): number;
310 | computeB(a: number, b: number, h: number): number;
311 | computeGq(): number;
312 | computeGW(): number;
313 | computeGWlambda(): number;
314 | computeGiMf(): number;
315 | computeGiMGt(): number;
316 | addToWlambda(deltalambda: number): number;
317 | computeInvC(eps: number): number;
318 |
319 | }
320 |
321 | export class FrictionEquation extends Equation {
322 |
323 | constructor(bodyA: Body, bodyB: Body, slipForce: number);
324 |
325 | contactPointA: number[];
326 | contactPointB: number[];
327 | t: number[];
328 | shapeA: Shape;
329 | shapeB: Shape;
330 | frictionCoefficient: number;
331 |
332 | setSlipForce(slipForce: number): number;
333 | getSlipForce(): number;
334 | computeB(a: number, b: number, h: number): number;
335 |
336 | }
337 |
338 | export class RotationalLockEquation extends Equation {
339 |
340 | constructor(bodyA: Body, bodyB: Body, options?: {
341 | angle?: number;
342 | });
343 |
344 | angle: number;
345 |
346 | computeGq(): number;
347 |
348 | }
349 |
350 | export class RotationalVelocityEquation extends Equation {
351 |
352 | constructor(bodyA: Body, bodyB: Body);
353 |
354 | computeB(a: number, b: number, h: number): number;
355 |
356 | }
357 |
358 | export class EventEmitter {
359 |
360 | on(type: string, listener: Function, context: any): EventEmitter;
361 | has(type: string, listener: Function): boolean;
362 | off(type: string, listener: Function): EventEmitter;
363 | emit(event: any): EventEmitter;
364 |
365 | }
366 |
367 | export class ContactMaterialOptions {
368 |
369 | friction: number;
370 | restitution: number;
371 | stiffness: number;
372 | relaxation: number;
373 | frictionStiffness: number;
374 | frictionRelaxation: number;
375 | surfaceVelocity: number;
376 |
377 | }
378 |
379 | export class ContactMaterial {
380 |
381 | static idCounter: number;
382 |
383 | constructor(materialA: Material, materialB: Material, options?: ContactMaterialOptions);
384 |
385 | id: number;
386 | materialA: Material;
387 | materialB: Material;
388 | friction: number;
389 | restitution: number;
390 | stiffness: number;
391 | relaxation: number;
392 | frictionStuffness: number;
393 | frictionRelaxation: number;
394 | surfaceVelocity: number;
395 | contactSkinSize: number;
396 |
397 | }
398 |
399 | export class Material {
400 |
401 | static idCounter: number;
402 |
403 | constructor(id: number);
404 |
405 | id: number;
406 |
407 | }
408 |
409 | export class vec2 {
410 |
411 | static crossLength(a: number[], b: number[]): number;
412 | static crossVZ(out: number[], vec: number[], zcomp: number): number;
413 | static crossZV(out: number[], zcomp: number, vec: number[]): number;
414 | static rotate(out: number[], a: number[], angle: number): void;
415 | static rotate90cw(out: number[], a: number[]): number;
416 | static centroid(out: number[], a: number[], b: number[], c: number[]): number[];
417 | static create(): number[];
418 | static clone(a: number[]): number[];
419 | static fromValues(x: number, y: number): number[];
420 | static copy(out: number[], a: number[]): number[];
421 | static set(out: number[], x: number, y: number): number[];
422 | static toLocalFrame(out: number[], worldPoint: number[], framePosition: number[], frameAngle: number): void;
423 | static toGlobalFrame(out: number[], localPoint: number[], framePosition: number[], frameAngle: number): void;
424 | static add(out: number[], a: number[], b: number[]): number[];
425 | static subtract(out: number[], a: number[], b: number[]): number[];
426 | static sub(out: number[], a: number[], b: number[]): number[];
427 | static multiply(out: number[], a: number[], b: number[]): number[];
428 | static mul(out: number[], a: number[], b: number[]): number[];
429 | static divide(out: number[], a: number[], b: number[]): number[];
430 | static div(out: number[], a: number[], b: number[]): number[];
431 | static scale(out: number[], a: number[], b: number): number[];
432 | static distance(a: number[], b: number[]): number;
433 | static dist(a: number[], b: number[]): number;
434 | static squaredDistance(a: number[], b: number[]): number;
435 | static sqrDist(a: number[], b: number[]): number;
436 | static length(a: number[]): number;
437 | static len(a: number[]): number;
438 | static squaredLength(a: number[]): number;
439 | static sqrLen(a: number[]): number;
440 | static negate(out: number[], a: number[]): number[];
441 | static normalize(out: number[], a: number[]): number[];
442 | static dot(a: number[], b: number[]): number;
443 | static str(a: number[]): string;
444 |
445 | }
446 |
447 | export class BodyOptions {
448 |
449 | mass: number;
450 | position: number[];
451 | velocity: number[];
452 | angle: number;
453 | angularVelocity: number;
454 | force: number[];
455 | angularForce: number;
456 | fixedRotation: number;
457 |
458 | }
459 |
460 | export class Body extends EventEmitter {
461 |
462 | sleepyEvent: {
463 | type: string;
464 | };
465 |
466 | sleepEvent: {
467 | type: string;
468 | };
469 |
470 | wakeUpEvent: {
471 | type: string;
472 | };
473 |
474 | static DYNAMIC: number;
475 | static STATIC: number;
476 | static KINEMATIC: number;
477 | static AWAKE: number;
478 | static SLEEPY: number;
479 | static SLEEPING: number;
480 |
481 | constructor(options?: BodyOptions);
482 |
483 | id: number;
484 | world: World;
485 | shapes: Shape[];
486 | shapeOffsets: number[][];
487 | shapeAngles: number[];
488 | mass: number;
489 | invMass: number;
490 | inertia: number;
491 | invInertia: number;
492 | invMassSolve: number;
493 | invInertiaSolve: number;
494 | fixedRotation: number;
495 | position: number[];
496 | interpolatedPosition: number[];
497 | interpolatedAngle: number;
498 | previousPosition: number[];
499 | previousAngle: number;
500 | velocity: number[];
501 | vlambda: number[];
502 | wlambda: number[];
503 | angle: number;
504 | angularVelocity: number;
505 | force: number[];
506 | angularForce: number;
507 | damping: number;
508 | angularDamping: number;
509 | type: number;
510 | boundingRadius: number;
511 | aabb: AABB;
512 | aabbNeedsUpdate: boolean;
513 | allowSleep: boolean;
514 | wantsToSleep: boolean;
515 | sleepState: number;
516 | sleepSpeedLimit: number;
517 | sleepTimeLimit: number;
518 | gravityScale: number;
519 |
520 | updateSolveMassProperties(): void;
521 | setDensity(density: number): void;
522 | getArea(): number;
523 | getAABB(): AABB;
524 | updateAABB(): void;
525 | updateBoundingRadius(): void;
526 | addShape(shape: Shape, offset?: number[], angle?: number): void;
527 | removeShape(shape: Shape): boolean;
528 | updateMassProperties(): void;
529 | applyForce(force: number[], worldPoint: number[]): void;
530 | toLocalFrame(out: number[], worldPoint: number[]): void;
531 | toWorldFrame(out: number[], localPoint: number[]): void;
532 | fromPolygon(path: number[][], options?: {
533 | optimalDecomp?: boolean;
534 | skipSimpleCheck?: boolean;
535 | removeCollinearPoints?: any; //boolean | number
536 | }): boolean;
537 | adjustCenterOfMass(): void;
538 | setZeroForce(): void;
539 | resetConstraintVelocity(): void;
540 | applyDamping(dy: number): void;
541 | wakeUp(): void;
542 | sleep(): void;
543 | sleepTick(time: number, dontSleep: boolean, dt: number): void;
544 | getVelocityFromPosition(story: number[], dt: number): number[];
545 | getAngularVelocityFromPosition(timeStep: number): number;
546 | overlaps(body: Body): boolean;
547 |
548 | }
549 |
550 | export class Spring {
551 |
552 | constructor(bodyA: Body, bodyB: Body, options?: {
553 |
554 | stiffness?: number;
555 | damping?: number;
556 | localAnchorA?: number[];
557 | localAnchorB?: number[];
558 | worldAnchorA?: number[];
559 | worldAnchorB?: number[];
560 |
561 | });
562 |
563 | stiffness: number;
564 | damping: number;
565 | bodyA: Body;
566 | bodyB: Body;
567 |
568 | applyForce(): void;
569 |
570 | }
571 |
572 | export class LinearSpring extends Spring {
573 |
574 | localAnchorA: number[];
575 | localAnchorB: number[];
576 | restLength: number;
577 |
578 | setWorldAnchorA(worldAnchorA: number[]): void;
579 | setWorldAnchorB(worldAnchorB: number[]): void;
580 | getWorldAnchorA(result: number[]): number[];
581 | getWorldAnchorB(result: number[]): number[];
582 | applyForce(): void;
583 |
584 | }
585 |
586 | export class RotationalSpring extends Spring {
587 |
588 | constructor(bodyA: Body, bodyB: Body, options?: {
589 | restAngle?: number;
590 | stiffness?: number;
591 | damping?: number;
592 | });
593 |
594 | restAngle: number;
595 |
596 | }
597 |
598 | export class Capsule extends Shape {
599 |
600 | constructor(length?: number, radius?: number);
601 |
602 | length: number;
603 | radius: number;
604 |
605 | }
606 |
607 | export class Circle extends Shape {
608 |
609 | constructor(radius: number);
610 |
611 | radius: number;
612 |
613 | }
614 |
615 | export class Convex extends Shape {
616 |
617 | static triangleArea(a: number[], b: number[], c: number[]): number;
618 |
619 | constructor(vertices: number[][], axes: number[]);
620 |
621 | vertices: number[][];
622 | axes: number[];
623 | centerOfMass: number[];
624 | triangles: number[];
625 | boundingRadius: number;
626 |
627 | projectOntoLocalAxis(localAxis: number[], result: number[]): void;
628 | projectOntoWorldAxis(localAxis: number[], shapeOffset: number[], shapeAngle: number, result: number[]): void;
629 |
630 | updateCenterOfMass(): void;
631 |
632 | }
633 |
634 | export class Heightfield extends Shape {
635 |
636 | constructor(data: number[], options?: {
637 | minValue?: number;
638 | maxValue?: number;
639 | elementWidth: number;
640 | });
641 |
642 | data: number[];
643 | maxValue: number;
644 | minValue: number;
645 | elementWidth: number;
646 |
647 | }
648 |
649 | export class Shape {
650 |
651 | static idCounter: number;
652 | static CIRCLE: number;
653 | static PARTICLE: number;
654 | static PLANE: number;
655 | static CONVEX: number;
656 | static LINE: number;
657 | static RECTANGLE: number;
658 | static CAPSULE: number;
659 | static HEIGHTFIELD: number;
660 |
661 | constructor(type: number);
662 |
663 | type: number;
664 | id: number;
665 | boundingRadius: number;
666 | collisionGroup: number;
667 | collisionMask: number;
668 | material: Material;
669 | area: number;
670 | sensor: boolean;
671 |
672 | computeMomentOfInertia(mass: number): number;
673 | updateBoundingRadius(): number;
674 | updateArea(): void;
675 | computeAABB(out: AABB, position: number[], angle: number): void;
676 |
677 | }
678 |
679 | export class Line extends Shape {
680 |
681 | constructor(length?: number);
682 |
683 | length: number;
684 |
685 | }
686 |
687 | export class Particle extends Shape {
688 |
689 | }
690 |
691 | export class Plane extends Shape {
692 |
693 | }
694 |
695 | export class Rectangle extends Shape {
696 |
697 | static sameDimensions(a: Rectangle, b: Rectangle): boolean;
698 |
699 | constructor(width?: number, height?: number);
700 |
701 | width: number;
702 | height: number;
703 |
704 | }
705 |
706 | export class Solver extends EventEmitter {
707 |
708 | static GS: number;
709 | static ISLAND: number;
710 |
711 | constructor(options?: {}, type?: number);
712 |
713 | type: number;
714 | equations: Equation[];
715 | equationSortFunction: Equation; //Equation | boolean
716 |
717 | solve(dy: number, world: World): void;
718 | solveIsland(dy: number, island: Island): void;
719 | sortEquations(): void;
720 | addEquation(eq: Equation): void;
721 | addEquations(eqs: Equation[]): void;
722 | removeEquation(eq: Equation): void;
723 | removeAllEquations(): void;
724 |
725 | }
726 |
727 | export class GSSolver extends Solver {
728 |
729 | constructor(options?: {
730 | iterations?: number;
731 | tolerance?: number;
732 | });
733 |
734 | iterations: number;
735 | tolerance: number;
736 | useZeroRHS: boolean;
737 | frictionIterations: number;
738 | usedIterations: number;
739 |
740 | solve(h: number, world: World): void;
741 |
742 | }
743 |
744 | export class OverlapKeeper {
745 |
746 | constructor(bodyA: Body, shapeA: Shape, bodyB: Body, shapeB: Shape);
747 |
748 | shapeA: Shape;
749 | shapeB: Shape;
750 | bodyA: Body;
751 | bodyB: Body;
752 |
753 | tick(): void;
754 | setOverlapping(bodyA: Body, shapeA: Shape, bodyB: Body, shapeB: Body): void;
755 | bodiesAreOverlapping(bodyA: Body, bodyB: Body): boolean;
756 | set(bodyA: Body, shapeA: Shape, bodyB: Body, shapeB: Shape): void;
757 |
758 | }
759 |
760 | export class TupleDictionary {
761 |
762 | data: number[];
763 | keys: number[];
764 |
765 | getKey(id1: number, id2: number): string;
766 | getByKey(key: number): number;
767 | get(i: number, j: number): number;
768 | set(i: number, j: number, value: number): number;
769 | reset(): void;
770 | copy(dict: TupleDictionary): void;
771 |
772 | }
773 |
774 | export class Utils {
775 |
776 | static appendArray(a: Array, b: Array): Array;
777 | static chanceRoll(chance: number): boolean;
778 | static defaults(options: any, defaults: any): any;
779 | static extend(a: any, b: any): void;
780 | static randomChoice(choice1: any, choice2: any): any;
781 | static rotateArray(matrix: any[], direction: any): any[];
782 | static splice(array: Array, index: number, howMany: number): void;
783 | static shuffle(array: T[]): T[];
784 | static transposeArray(array: T[]): T[];
785 |
786 | }
787 |
788 | export class Island {
789 |
790 | equations: Equation[];
791 | bodies: Body[];
792 |
793 | reset(): void;
794 | getBodies(result: any): Body[];
795 | wantsToSleep(): boolean;
796 | sleep(): boolean;
797 |
798 | }
799 |
800 | export class IslandManager extends Solver {
801 |
802 | static getUnvisitedNode(nodes: Node[]): IslandNode; // IslandNode | boolean
803 |
804 | equations: Equation[];
805 | islands: Island[];
806 | nodes: IslandNode[];
807 |
808 | visit(node: IslandNode, bds: Body[], eqs: Equation[]): void;
809 | bfs(root: IslandNode, bds: Body[], eqs: Equation[]): void;
810 | split(world: World): Island[];
811 |
812 | }
813 |
814 | export class IslandNode {
815 |
816 | constructor(body: Body);
817 |
818 | body: Body;
819 | neighbors: IslandNode[];
820 | equations: Equation[];
821 | visited: boolean;
822 |
823 | reset(): void;
824 |
825 | }
826 |
827 | export class World extends EventEmitter {
828 |
829 | postStepEvent: {
830 | type: string;
831 | };
832 |
833 | addBodyEvent: {
834 | type: string;
835 | };
836 |
837 | removeBodyEvent: {
838 | type: string;
839 | };
840 |
841 | addSpringEvent: {
842 | type: string;
843 | };
844 |
845 | impactEvent: {
846 | type: string;
847 | bodyA: Body;
848 | bodyB: Body;
849 | shapeA: Shape;
850 | shapeB: Shape;
851 | contactEquation: ContactEquation;
852 | };
853 |
854 | postBroadphaseEvent: {
855 | type: string;
856 | pairs: Body[];
857 | };
858 |
859 | beginContactEvent: {
860 | type: string;
861 | shapeA: Shape;
862 | shapeB: Shape;
863 | bodyA: Body;
864 | bodyB: Body;
865 | contactEquations: ContactEquation[];
866 | };
867 |
868 | endContactEvent: {
869 | type: string;
870 | shapeA: Shape;
871 | shapeB: Shape;
872 | bodyA: Body;
873 | bodyB: Body;
874 | };
875 |
876 | preSolveEvent: {
877 | type: string;
878 | contactEquations: ContactEquation[];
879 | frictionEquations: FrictionEquation[];
880 | };
881 |
882 | static NO_SLEEPING: number;
883 | static BODY_SLEEPING: number;
884 | static ISLAND_SLEEPING: number;
885 |
886 | static integrateBody(body: Body, dy: number): void;
887 |
888 | constructor(options?: {
889 | solver?: Solver;
890 | gravity?: number[];
891 | broadphase?: Broadphase;
892 | islandSplit?: boolean;
893 | doProfiling?: boolean;
894 | });
895 |
896 | springs: Spring[];
897 | bodies: Body[];
898 | solver: Solver;
899 | narrowphase: Narrowphase;
900 | islandManager: IslandManager;
901 | gravity: number[];
902 | frictionGravity: number;
903 | useWorldGravityAsFrictionGravity: boolean;
904 | useFrictionGravityOnZeroGravity: boolean;
905 | doProfiling: boolean;
906 | lastStepTime: number;
907 | broadphase: Broadphase;
908 | constraints: Constraint[];
909 | defaultMaterial: Material;
910 | defaultContactMaterial: ContactMaterial;
911 | lastTimeStep: number;
912 | applySpringForces: boolean;
913 | applyDamping: boolean;
914 | applyGravity: boolean;
915 | solveConstraints: boolean;
916 | contactMaterials: ContactMaterial[];
917 | time: number;
918 | stepping: boolean;
919 | islandSplit: boolean;
920 | emitImpactEvent: boolean;
921 | sleepMode: number;
922 |
923 | addConstraint(c: Constraint): void;
924 | addContactMaterial(contactMaterial: ContactMaterial): void;
925 | removeContactMaterial(cm: ContactMaterial): void;
926 | getContactMaterial(materialA: Material, materialB: Material): ContactMaterial; // ContactMaterial | boolean
927 | removeConstraint(c: Constraint): void;
928 | step(dy: number, timeSinceLastCalled?: number, maxSubSteps?: number): void;
929 | runNarrowphase(np: Narrowphase, bi: Body, si: Shape, xi: any[], ai: number, bj: Body, sj: Shape, xj: any[], aj: number, cm: number, glen: number): void;
930 | addSpring(s: Spring): void;
931 | removeSpring(s: Spring): void;
932 | addBody(body: Body): void;
933 | removeBody(body: Body): void;
934 | getBodyByID(id: number): Body; //Body | boolean
935 | disableBodyCollision(bodyA: Body, bodyB: Body): void;
936 | enableBodyCollision(bodyA: Body, bodyB: Body): void;
937 | clear(): void;
938 | clone(): World;
939 | hitTest(worldPoint: number[], bodies: Body[], precision: number): Body[];
940 | setGlobalEquationParameters(parameters: {
941 | relaxation?: number;
942 | stiffness?: number;
943 | }): void;
944 | setGlobalStiffness(stiffness: number): void;
945 | setGlobalRelaxation(relaxation: number): void;
946 | }
947 |
948 | }
949 |
--------------------------------------------------------------------------------
/src/types/phaser_box2d.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | declare module Phaser {
5 |
6 | module Physics {
7 |
8 | class Box2D {
9 |
10 | constructor(game: Phaser.Game, config?: any);
11 |
12 | // @property {Phaser.Game} game - Local reference to game.
13 | game: Phaser.Game;
14 | // @property {string} version - The version of the Box2D Plugin that is running.
15 | version: string;
16 | // @property {number} ptmRatio - Pixels to Meters ratio - @default 50
17 | ptmRatio: number;
18 | // @property {box2d.b2World} world - The Box2D world in which the simulation is run.
19 | world: box2d.b2World;
20 | // @property {Phaser.Physics.Box2D.DefaultDebugDraw} - used for rendering debug information
21 | debugDraw: Box2D.DefaultDebugDraw;
22 | // @property {Phaser.Physics.Box2D.DefaultContactListener} - used to check if bodies have contact callbacks set
23 | contactListener: Box2D.DefaultContactListener;
24 | // @property {number} nextBodyId - The id to give the next created body
25 | nextBodyId: number;
26 | // @property {number} nextFixtureId - The id to give the next created fixture
27 | nextFixtureId: number;
28 | // @property {box2d.b2Vec2} gravity - The gravity of the Box2D world.
29 | gravity: Box2D.PointProxy;
30 | // @property {number} friction - The default friction for fixtures created by 'enable', or other functions like setRectangle, setPolygon etc
31 | friction: number;
32 | // @property {number} restitution - The default restitution for fixtures created by 'enable', or other functions like setRectangle, setPolygon etc
33 | restitution: number;
34 | // @property {number} density - The default density for fixtures created by 'enable', or other functions like setRectangle, setPolygon etc
35 | density: number;
36 | // @property {number} frameRate - The frame rate the world will be stepped at. Defaults to 1 / 60, but you can change here. Also see useElapsedTime property.
37 | frameRate: number;
38 | // @property {number} velocityIterations - The maximum number of iterations allowed to adjust velocities to match constraints. Defaults to 8.
39 | velocityIterations: number;
40 | // @property {number} positionIterations - The maximum number of iterations allowed to adjust positions to match constraints. Defaults to 3.
41 | positionIterations: number;
42 | // @property {boolean} useElapsedTime - If true the frameRate value will be ignored and instead Box2D will step with the value of Game.Time.physicsElapsed, which is a delta time value.
43 | useElapsedTime: boolean;
44 | // @property {boolean} paused - The paused state of the Box2D world.
45 | paused: boolean;
46 | // @property {box2d.b2ParticleSystem} particleSystem - The World Particle System. Enabled with World.createParticleSystem.
47 | particleSystem: box2d.b2ParticleSystem;
48 | // @property {box2d.b2Body} mouseJointBody - A static body with no fixtures, used internally as the 'body A' for mouse joints when dragging dynamic bodies.
49 | mouseJointBody: box2d.b2Body;
50 | // @property {box2d.b2MouseJoint} mouseJoint - The active mouse joint for dragging dynamic bodies.
51 | mouseJoint: box2d.b2MouseJoint;
52 | // Pixel to meter function overrides.
53 | // mpx: Function;
54 | // pxm: Function;
55 | // @property {object} walls - An object containing the 4 wall bodies that bound the physics world.
56 | walls: Box2D.WallsObject;
57 | // @property {Phaser.Signal} onBodyAdded - Dispatched when a new Body is added to the World.
58 | onBodyAdded: Phaser.Signal;
59 | // @property {Phaser.Signal} onBodyRemoved - Dispatched when a Body is removed from the World.
60 | onBodyRemoved: Phaser.Signal;
61 |
62 | static worldBoundsFilterCategory: number;
63 |
64 | // Returns the next id to use to keep body ids unique
65 | getNextBodyId(): number;
66 | // Returns the next id to use to keep fixture ids unique
67 | getNextFixtureId(): number;
68 | // This will add a Box2D physics body into the removal list for the next step.
69 | removeBodyNextStep(body: Box2D.Body): void;
70 | // Called at the start of the core update loop. Purges flagged bodies from the world.
71 | preUpdate(): void;
72 | // This will create a Box2D physics body on the given game object or array of game objects.
73 | // A game object can only have 1 physics body active at any one time, and it can't be changed until the object is destroyed.
74 | // Note: When the game object is enabled for Box2D physics it has its anchor x/y set to 0.5 so it becomes centered.
75 | enable(object: any, children?: boolean): void;
76 | // Creates a Box2D physics body on the given game object.
77 | // A game object can only have 1 physics body active at any one time, and it can't be changed until the body is nulled.
78 | enableBody(object: any): void;
79 | // Sets the bounds of the Physics world to match the Game.World dimensions.
80 | // You can optionally set which 'walls' to create: left, right, top or bottom.
81 | setBoundsToWorld(left?: boolean, right?: boolean, top?: boolean, bottom?: boolean, collisionCategory?: number, collisionMask?: number): void;
82 | // Sets the bounds of the Physics world to match the given world pixel dimensions.
83 | // You can optionally set which 'walls' to create: left, right, top or bottom.
84 | setBounds(x: number, y: number, width: number, height: number,
85 | left?: boolean, right?: boolean, top?: boolean, bottom?: boolean, collisionCategory?: number, collisionMask?: number): void;
86 | // Pauses the Box2D world independent of the game pause state.
87 | pause(): void;
88 | // Resumes a paused Box2D world.
89 | resume(): void;
90 | // Internal Box2D update loop.
91 | update(): void;
92 | // Clears all bodies from the simulation, resets callbacks.
93 | reset(): void;
94 | // Clears all bodies from the simulation, resets callbacks.
95 | clear(): void;
96 | // Clears all bodies from the simulation and unlinks World from Game. Should only be called on game shutdown. Call `clear` on a State change.
97 | destroy(): void;
98 | // Creates a new Body and adds it to the World.
99 | createBody(x?: number, y?: number, density?: number): Box2D.Body;
100 | // Creates a new dynamic Body and adds a Circle fixture to it of the given size.
101 | createCircle(x?: number, y?: number, radius?: number, offsetX?: number, offsetY?: number): Box2D.Body;
102 | // Creates a new dynamic Body and adds a Rectangle fixture to it of the given dimensions.
103 | createRectangle(x?: number, y?: number, width?: number, height?: number, offsetX?: number, offsetY?: number, rotation?: number): Box2D.Body;
104 | // Creates a new dynamic Body and adds a Polygon fixture to it.
105 | createPolygon(x: number, y: number, vertices: number[], firstIndex?: number, count?: number): Box2D.Body;
106 | // Adds an already created Box2D Body to this Box2D world.
107 | addBody(body: Box2D.Body): boolean;
108 | // Removes a body from the world. This will silently fail if the body wasn't part of the world to begin with.
109 | removeBody(body: Box2D.Body): Box2D.Body;
110 | // Populates and returns an array with references to of all current Bodies in the world.
111 | getBodies(): Box2D.Body[];
112 | // Checks the given object to see if it has a Box2D body and if so returns it.
113 | getBody(object: Object): Box2D.Body;
114 | // Converts the current world into a JSON object.
115 | toJSON(): any;
116 | // Convert Box2D physics value (meters) to pixel scale.
117 | // By default we use a scale of 50px per meter.
118 | // If you need to modify this you can over-ride these functions via the Physics Configuration object.
119 | mpx(v: number): number;
120 | // Convert pixel value to Box2D physics scale (meters).
121 | // By default we use a scale of 50px per meter.
122 | // If you need to modify this you can over-ride these functions via the Physics Configuration object.
123 | pxm(v: number): number;
124 | // Runs the standard 'debug draw' rendering. What actually gets drawn will depend
125 | // on the current status of the flags set in the debug draw object held by the b2World.
126 | // This could perhaps be made modifiable at runtime, but for now it is just rendering
127 | // shapes (see usage of b2Shapes flag below).
128 | renderDebugDraw(context: CanvasRenderingContext2D): void;
129 | // Renders information about the body as text. This is intended to be used internally by Phaser.Utils.Debug.
130 | // To make use of this from your code you would call something like game.debug.bodyInfo(sprite, x, y)
131 | renderBodyInfo(debug: Utils.Debug, body: Box2D.Body): void;
132 | // Returns all fixtures found under the given point. Set the onlyOne parameter to true if you only
133 | // care about finding one fixture under the point.
134 | getFixturesAtPoint(x: number, y: number, onlyOne?: boolean, onlyDynamic?: boolean): box2d.b2Fixture[];
135 | // Returns all bodies (Phaser.Physics.Box2D.Body) found under the given coordinates. Set the onlyOne
136 | // parameter to true if you only care about finding one body.
137 | getBodiesAtPoint(x: number, y: number, onlyOne?: boolean, onlyDynamic?: boolean): box2d.b2Body[];
138 |
139 | // If there is a dynamic body under the given point, a mouse joint will be created
140 | // to drag that body around. Use the mouseDragMove and mouseDragEnd functions to
141 | // continue the drag action. Any mouse drag already in progress will be canceled.
142 | mouseDragStart(point: Phaser.Point): void;
143 | // Updates the target location of the active mouse joint, if there is one. If there
144 | // is no mouse joint active, this does nothing.
145 | mouseDragMove(point: Phaser.Point): void;
146 | // Ends the active mouse joint if there is one. If there is no mouse joint active, does nothing.
147 | mouseDragEnd(): void;
148 |
149 | // Creates a distance joint.
150 | distanceJoint(bodyA: Box2D.Body | Phaser.Sprite, bodyB: Box2D.Body | Phaser.Sprite, length?: number,
151 | ax?: number, ay?: number, bx?: number, by?: number, frequency?: number, damping?: number): box2d.b2DistanceJoint;
152 | // Creates a rope joint.
153 | ropeJoint(bodyA: Box2D.Body | Phaser.Sprite, bodyB: Box2D.Body | Phaser.Sprite, length?: number,
154 | ax?: number, ay?: number, bx?: number, by?: number): box2d.b2RopeJoint;
155 | // Creates a revolute joint.
156 | revoluteJoint(bodyA: Box2D.Body | Phaser.Sprite, bodyB: Box2D.Body | Phaser.Sprite,
157 | ax?: number, ay?: number, bx?: number, by?: number,
158 | motorSpeed?: number, motorTorque?: number, motorEnabled?: boolean,
159 | lowerLimit?: number, upperLimit?: number, limitEnabled?: boolean): box2d.b2RevoluteJoint;
160 | // Creates a prismatic joint.
161 | prismaticJoint(bodyA: Box2D.Body | Phaser.Sprite, bodyB: Box2D.Body | Phaser.Sprite,
162 | axisX?: number, axisY?: number,
163 | ax?: number, ay?: number, bx?: number, by?: number,
164 | motorSpeed?: number, motorForce?: number, motorEnabled?: boolean,
165 | owerLimit?: number, upperLimit?: number, limitEnabled?: boolean,
166 | offsetAngle?:number): box2d.b2PrismaticJoint;
167 | // Creates a friction joint.
168 | frictionJoint(bodyA: Box2D.Body | Phaser.Sprite, bodyB: Box2D.Body | Phaser.Sprite,
169 | maxForce?:number, maxTorque?:number,
170 | ax?: number, ay?: number, bx?: number, by?: number): box2d.b2FrictionJoint;
171 | // Creates a weld joint.
172 | weldJoint(bodyA: Box2D.Body | Phaser.Sprite, bodyB: Box2D.Body | Phaser.Sprite,
173 | ax?: number, ay?: number, bx?: number, by?: number,
174 | frequency?:number, damping?:number): box2d.b2WeldJoint;
175 | // Creates a motor joint.
176 | motorJoint(bodyA: Box2D.Body | Phaser.Sprite, bodyB: Box2D.Body | Phaser.Sprite,
177 | maxForce? :number, maxTorque?:number, correctionFactor?:number,
178 | offsetX?:number, offsetY?:number,
179 | offsetAngle?: number): box2d.b2MotorJoint;
180 | // Creates a wheel joint.
181 | wheelJoint(bodyA: Box2D.Body | Phaser.Sprite, bodyB: Box2D.Body | Phaser.Sprite,
182 | ax?: number, ay?: number, bx?: number, by?: number,
183 | axisX?: number, axisY?: number,
184 | frequency?: number, damping?: number, motorSpeed?: number, motorTorque?: number, motorEnabled?: boolean): box2d.b2WheelJoint;
185 | // Creates a pulley joint.
186 | pulleyJoint(bodyA: Box2D.Body | Phaser.Sprite, bodyB: Box2D.Body | Phaser.Sprite,
187 | ax?: number, ay?: number, bx?: number, by?: number,
188 | gax?: number, gay?: number, gbx?: number, gby?: number,
189 | ratio?: number, lengthA?: number, lengthB?: number): box2d.b2PulleyJoint;
190 | // Creates a gear joint.
191 | gearJoint(joint1: box2d.b2Joint, joint2: box2d.b2Joint, ratio?:number): box2d.b2GearJoint;
192 |
193 |
194 | // Clears all physics bodies from the given TilemapLayer that were created with `World.convertTilemap`.
195 | clearTilemapLayerBodies(map: Phaser.Tilemap, layer: number | string | Phaser.TilemapLayer): void;
196 | // Goes through all tiles in the given Tilemap and TilemapLayer and converts those set to collide into physics bodies.
197 | // Only call this *after* you have specified all of the tiles you wish to collide with calls like Tilemap.setCollisionBetween, etc.
198 | // Every time you call this method it will destroy any previously created bodies and remove them from the world.
199 | // Therefore understand it's a very expensive operation and not to be done in a core game update loop.
200 | convertTilemap(map: Phaser.Tilemap, layer: number | string | Phaser.TilemapLayer, addToWorld?: boolean, optimize?: boolean): Box2D.Body[];
201 |
202 | // Casts a ray and finds intersecting fixtures in the world.
203 | raycast(x1: number, y1: number, x2: number, y2: number, closestHitOnly?: boolean, filterFunction?: Function): Box2D.RaycastHit[];
204 | // Finds all fixtures with AABBs overlapping the given area. This does NOT mean
205 | // that the fixtures themselves are actually overlapping the given area.
206 | queryAABB(x: number, y: number, width: number, height: number): Box2D.AABBHit[];
207 | // Finds all fixtures that overlap the given fixture.
208 | queryFixture(fixture: box2d.b2Fixture): Box2D.AABBHit[];
209 |
210 | // If the PTM ratio is changed after creating the world, the debug draw scale needs to be updated.
211 | setPTMRatio(newRatio: number): void;
212 | }
213 |
214 |
215 | module Box2D {
216 |
217 | class DefaultDebugDraw {
218 |
219 | constructor(pixelsPerMeter: number);
220 |
221 | color: box2d.b2Color;
222 |
223 | // Sets which aspects of the world to render
224 | SetFlags(flags: number): void;
225 | // Gets which aspects of the world are currently set to be rendered
226 | GetFlags(): number;
227 | // Sets the canvas context to use in subsequent rendering and applies overall transform.
228 | start(context: CanvasRenderingContext2D): void;
229 | // Resets transform state to original
230 | stop(): void;
231 | // Push transform
232 | PushTransform(xf: box2d.b2Transform): void;
233 | // Pop transform
234 | PopTransform(): box2d.b2Transform;
235 | // Draw polygon
236 | DrawPolygon(vertices: Array, vertexCount: number, color: box2d.b2Color): void;
237 | // Draw solid polygon
238 | DrawSolidPolygon(vertices: Array, vertexCount: number, color: box2d.b2Color): void;
239 | // Draw circle
240 | DrawCircle(center: box2d.b2Vec2, radius: number, color: box2d.b2Color): void;
241 | // Draw solid circle
242 | DrawSolidCircle(center: box2d.b2Vec2, radius: number, axis: box2d.b2Vec2, color: box2d.b2Color): void;
243 | // Draw segment
244 | DrawSegment(p1: box2d.b2Vec2, p2: box2d.b2Vec2, color: box2d.b2Color): void;
245 | // Draw transform
246 | DrawTransform(xf: box2d.b2Transform): void;
247 | // Draw point
248 | DrawPoint(p: box2d.b2Vec2, size: number, color: box2d.b2Color): void;
249 | // Draw AABB
250 | DrawAABB(aabb: box2d.b2AABB, color: box2d.b2Color): void;
251 |
252 | // shapes - Specifies whether the debug draw should render shapes.
253 | shapes: boolean;
254 | // joints - Specifies whether the debug draw should render joints.
255 | joints: boolean;
256 | // @property {boolean} aabbs - Specifies whether the debug draw should render fixture AABBs.
257 | aabbs: boolean;
258 | // @property {boolean} pairs - Specifies whether the debug draw should render contact pairs.
259 | pairs: boolean;
260 | // @property {boolean} centerOfMass - Specifies whether the debug draw should render the center of mass of bodies.
261 | centerOfMass: boolean;
262 | }
263 |
264 |
265 | class DefaultContactListener {
266 |
267 | constructor();
268 |
269 | // Called when two fixtures begin to touch.
270 | BeginContact(contact: box2d.b2Contact): void;
271 | // Called when two fixtures cease touching.
272 | EndContact(contact: box2d.b2Contact): void;
273 | // Common code for begin and end contacts.
274 | handleContactBeginOrEnd(contact: box2d.b2Contact, begin: boolean): void;
275 | // This is called after a contact is updated. This allows you to
276 | // inspect a contact before it goes to the solver. If you are
277 | // careful, you can modify the contact manifold (e.g. disable contact).
278 | PreSolve(contact: box2d.b2Contact, oldManifold: box2d.b2Manifold): void;
279 | // This lets you inspect a contact after the solver is finished.
280 | PostSolve(contact: box2d.b2Contact, impulse: box2d.b2ContactImpulse): void;
281 | }
282 |
283 |
284 | class PointProxy {
285 |
286 | constructor(world: Physics.Box2D, object: any, gettor: Function, settor: Function);
287 |
288 | x: number;
289 | y: number;
290 | }
291 |
292 |
293 | class Body {
294 |
295 | constructor(game: Phaser.Game, sprite: Phaser.Sprite, x?: number, y?: number, density?: number, world?: Physics.Box2D);
296 |
297 | // @property {Phaser.Game} game - Local reference to game.
298 | game: Phaser.Game;
299 | // @property {Phaser.Physics.Box2D} world - Local reference to the Box2D World.
300 | world: Physics.Box2D;
301 | // @property {number} id - a unique id for this body in the world
302 | id: number;
303 | // @property {Phaser.Sprite} sprite - Reference to the parent Sprite.
304 | sprite: Phaser.Sprite;
305 | // @property {number} type - The type of physics system this body belongs to.
306 | type: number;
307 | // @property {Phaser.Point} offset - The offset of the Physics Body from the Sprite x/y position.
308 | offset: Phaser.Point;
309 | // @property {box2d.b2BodyDef} bodyDef - The Box2D body definition
310 | bodyDef: box2d.b2BodyDef;
311 | // @property {box2d.b2Body} data - The Box2D body data.
312 | data: box2d.b2Body;
313 | // @property {Phaser.Physics.Box2D.PointProxy} velocity - The velocity of the body. Set velocity.x to a negative value to move to the left, position to the right. velocity.y negative values move up, positive move down.
314 | velocity: Box2D.PointProxy;
315 | // @property {boolean} removeNextStep - To avoid deleting this body during a physics step, and causing all kinds of problems, set removeNextStep to true to have it removed in the next preUpdate.
316 | removeNextStep: boolean;
317 |
318 | // Sets a callback to be fired any time a fixture in this Body begins or ends contact with a fixture in the given Body.
319 | setBodyContactCallback(object: Phaser.Sprite | Box2D.Body, callback: Function, callbackContext: any): void;
320 | // Sets a callback to be fired any time the given fixture begins or ends contact something
321 | setFixtureContactCallback(fixture: box2d.b2Fixture, callback: Function, callbackContext: any): void;
322 | // Sets a callback to be fired any time a fixture in this body begins contact with a fixture in another body that matches given category set.
323 | setCategoryContactCallback(category: number, callback: Function, callbackContext: any) : void;
324 | // Sets a callback to be fired when PreSolve is done for contacts between a fixture in this body and a fixture in the given Body.
325 | setBodyPresolveCallback(object: Phaser.Sprite | Box2D.Body, callback: Function, callbackContext: any): void;
326 | // Sets a callback to be fired when PreSolve is done for contacts between a fixture in this body the given fixture.
327 | setFixturePresolveCallback(fixture: box2d.b2Fixture, callback: Function, callbackContext:any) : void;
328 | // Sets a callback to be fired when PreSolve is done for contacts between a fixture in this body and a fixture in another body that matches given category set.
329 | setCategoryPresolveCallback(category: number, callback: Function, callbackContext: any) : void;
330 | // Sets a callback to be fired when PostSolve is done for contacts between a fixture in this body and a fixture in the given Body.
331 | setBodyPostsolveCallback(object: Phaser.Sprite | Box2D.Body, callback: Function, callbackContext:any) : void;
332 | // Sets a callback to be fired when PostSolve is done for contacts between a fixture in this body the given fixture.
333 | setFixturePostsolveCallback(fixture: box2d.b2Fixture, callback: Function, callbackContext: any): void;
334 | // Sets a callback to be fired when PostSolve is done for contacts between a fixture in this body and a fixture in another body that matches given category set.
335 | setCategoryPostsolveCallback(category: number, callback:Function, callbackContext:any): void;
336 |
337 | // Sets the given collision category for all fixtures in this Body, unless a specific fixture is given.
338 | setCollisionCategory(category: number, fixture?: box2d.b2Fixture): void;
339 | // Sets the given collision mask for all fixtures in this Body, unless a specific fixture is given.
340 | setCollisionMask(mask: number, fixture?: box2d.b2Fixture): void;
341 |
342 | // Apply force at the center of mass. This will not cause any rotation.
343 | applyForce(x: number, y: number): void;
344 | // If this Body is dynamic then this will zero its angular velocity.
345 | setZeroRotation(): void;
346 | // If this Body is dynamic then this will zero its velocity on both axis.
347 | setZeroVelocity(): void;
348 | // Sets the linear damping and angular damping to zero.
349 | setZeroDamping(): void;
350 |
351 | // Transform a world point to local body frame.
352 | toLocalPoint(out: box2d.b2Vec2, worldPoint: box2d.b2Vec2): box2d.b2Vec2;
353 | // Transform a local point to world frame.
354 | toWorldPoint(out: box2d.b2Vec2, localPoint: box2d.b2Vec2): box2d.b2Vec2;
355 | // Transform a world vector to local body frame.
356 | toLocalVector(out: box2d.b2Vec2, worldVector: box2d.b2Vec2): box2d.b2Vec2;
357 | // Transform a local vector to world frame.
358 | toWorldVector(out: box2d.b2Vec2, localVector: box2d.b2Vec2): box2d.b2Vec2;
359 |
360 | // This will rotate the Body by the given speed to the left (counter-clockwise).
361 | rotateLeft(speed: number): void;
362 | // This will rotate the Body by the given speed to the left (clockwise).
363 | rotateRight(speed: number): void;
364 | // Moves the Body forwards based on its current angle and the given speed.
365 | // The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second.
366 | moveForward(speed: number): void;
367 | // Moves the Body backwards based on its current angle and the given speed.
368 | // The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second.
369 | moveBackward(speed: number): void;
370 | // Applies a force to the Body that causes it to 'thrust' forwards, based on its current angle and the given speed.
371 | thrust(power: number): void;
372 | // Applies a force to the Body that causes it to 'thrust' backwards (in reverse), based on its current angle and the given speed.
373 | reverse(power: number): void;
374 | // If this Body is dynamic then this will move it to the left by setting its x velocity to the given speed.
375 | // The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second.
376 | moveLeft(speed: number): void;
377 | // If this Body is dynamic then this will move it to the right by setting its x velocity to the given speed.
378 | // The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second.
379 | moveRight(speed: number): void;
380 | // If this Body is dynamic then this will move it up by setting its y velocity to the given speed.
381 | // The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second.
382 | moveUp(speed: number): void;
383 | // If this Body is dynamic then this will move it down by setting its y velocity to the given speed.
384 | // The speed is represented in pixels per second. So a value of 100 would move 100 pixels in 1 second.
385 | moveDown(speed: number): void;
386 |
387 | // Internal method. This is called directly before the sprites are sent to the renderer and after the update function has finished.
388 | // preUpdate(): void;
389 | // Internal method. This is called directly before the sprites are sent to the renderer and after the update function has finished.
390 | // postUpdate(): void;
391 |
392 | // Sets this body as inactive. It will not participate in collisions or
393 | // any other aspect of the physics simulation. Intended for use by Phaser.Sprite.kill()
394 | kill(): void;
395 | // Restores the active status of this body.
396 | reset(x: number, y: number): void;
397 | // Removes this physics body from the world.
398 | removeFromWorld(): void;
399 | // Destroys this Body and all references it holds to other objects.
400 | destroy(): void;
401 |
402 | // Removes all fixtures from this Body.
403 | clearFixtures(): void;
404 | // Adds a Circle fixture to this Body. You can control the offset from the center of the body and the rotation.
405 | // It will use the World friction, restitution and density by default.
406 | addCircle(radius:number, offsetX ?:number, offsetY ?:number): box2d.b2Fixture;
407 | // Adds a Rectangle fixture to this Body. You can control the offset from the center of the body and the rotation.
408 | // It will use the World friction, restitution and density by default.
409 | addRectangle(width ?:number, height ?:number, offsetX ?:number, offsetY ?:number, rotation ?:number): box2d.b2Fixture;
410 | // Creates a new Edge Shape and adds it to this Body.
411 | // It will use the World friction, restitution and density by default.
412 | addEdge(x1 ?:number, y1 ?:number, x2 ?:number, y2 ?:number): box2d.b2Fixture;
413 | // Creates a new chain shape and adds it to this Body.
414 | // It will use the World friction, restitution and density by default.
415 | addChain(vertices: number[], firstIndex ?:number, count ?:number, loop ?:boolean): box2d.b2Fixture;
416 | // Creates a new loop shape and adds it to this Body.
417 | addLoop(vertices: number[], firstIndex ?:number, count ?:number): box2d.b2Fixture;
418 | // Creates a new polygon shape and adds it to this Body.
419 | addPolygon(vertices: number[], firstIndex ?: number, count ?:number): box2d.b2Fixture;
420 | // Remove a shape from the body. Will automatically update the mass properties and bounding radius.
421 | removeFixture(fixture: box2d.b2Fixture): boolean;
422 | // Clears any previously set fixtures. Then creates a new Circle shape and adds it to this Body.
423 | setCircle(radius ?:number, offsetX ?:number, offsetY ?:number): box2d.b2Fixture;
424 | // Clears any previously set fixtures. The creates a new Rectangle fixture at the given size and offset, and adds it to this Body.
425 | // If you wish to create a Rectangle to match the size of a Sprite or Image see Body.setRectangleFromSprite.
426 | setRectangle(width ?:number, height ?:number, offsetX ?:number, offsetY ?:number, rotation ?:number): box2d.b2Fixture;
427 | // Clears any previously set fixtures.
428 | // Then creates a Rectangle shape sized to match the dimensions and orientation of the Sprite given.
429 | // If no Sprite is given it defaults to using the parent of this Body.
430 | setRectangleFromSprite(sprite: Phaser.Sprite | Phaser.Image): box2d.b2Fixture;
431 | // Clears any previously set fixtures. Then creates a new edge shape and adds it to this Body.
432 | setEdge(x1 ?:number, y1 ?:number, x2 ?:number, y2?:number): box2d.b2Fixture;
433 | // Clears any previously set fixtures. Then creates a new chain shape and adds it to this Body.
434 | setChain(vertices: number[], firstIndex?:number, count?:number, loop?:boolean): box2d.b2Fixture;
435 | // An alias for setChain.
436 | setLoop(vertices: number[], firstIndex?:number, count?:number): box2d.b2Fixture;
437 | // Clears any previously set fixtures. Then creates a new polygon shape and adds it to this Body.
438 | setPolygon(vertices: number[], firstIndex?: number, count?: number): box2d.b2Fixture;
439 | // Reads the shape data from a physics data file stored in the Game.Cache and adds it as a polygon to this Body.
440 | loadPolygon(key: string, object: string, sprite: Phaser.Sprite | Phaser.Image):boolean;
441 |
442 |
443 | // Checks if the given point (pixel coords) is contained by any of the fixtures on this body.
444 | // Not efficient for checking a large number of bodies to find which is under the mouse. (Use
445 | // Phaser.Physics.Box2D.getBodiesAtPoint for that.)
446 | containsPoint(point: Phaser.Point): boolean;
447 |
448 | // @property {boolean} static - Returns true if the Body is static. Setting Body.static to 'false' will make it dynamic.
449 | static: boolean;
450 | // @property {boolean} dynamic - Returns true if the Body is dynamic. Setting Body.dynamic to 'false' will make it static.
451 | dynamic: boolean;
452 | // @property {boolean} kinematic - Returns true if the Body is kinematic. Setting Body.kinematic to 'false' will make it static.
453 | kinematic: boolean;
454 |
455 | // @property {number} angle - The angle of this Body in degrees.
456 | angle: number;
457 | // @property {number} linearDamping - The linear damping acting acting on the body.
458 | linearDamping: number;
459 | // @property {number} angularDamping - The angular damping acting acting on the body.
460 | angularDamping: number;
461 | // @property {number} angularVelocity - The angular velocity of the body.
462 | angularVelocity: number;
463 | // @property {boolean} fixedRotation - If true, the body will not rotate.
464 | fixedRotation: boolean;
465 | // @property {number} gravityScale - Set to zero to completely ignore gravity, or negative values to reverse gravity for this body.
466 | gravityScale: number;
467 | // @property {number} friction - When setting, all fixtures on the body will be set to the given friction. When getting, the friction of the first fixture will be returned, or zero if no fixtures are present.
468 | friction: number;
469 | // @property {number} restitution - When setting, all fixtures on the body will be set to the given restitution. When getting, the restitution of the first fixture will be returned, or zero if no fixtures are present.
470 | restitution: number;
471 | // @property {boolean} sensor - When setting, all fixtures on the body will be set to the given sensor status. When getting, the sensor status of the first fixture will be returned, or false if no fixtures are present.
472 | sensor: boolean;
473 | // @property {boolean} bullet - Set to true to give the body 'bullet' status, and use continous collision detection when moving it.
474 | bullet: boolean;
475 | // @property {number} mass - the new mass for the body. Setting this to zero will cause the body to become a static body.
476 | mass: number;
477 | // @property {number} rotation - The angle of this Body in radians.
478 | rotation: number;
479 | // @property {number} x - The x coordinate of this Body.
480 | x: number;
481 | // @property {number} y - The y coordinate of this Body.
482 | y: number;
483 | // @property {boolean} collideWorldBounds - Should the Body collide with the World bounds?
484 | collideWorldBounds: boolean;
485 | }
486 |
487 |
488 | class WallsObject {
489 | left: any;
490 | right: any;
491 | top: any;
492 | bottom: any;
493 | }
494 |
495 |
496 | class AABBHit {
497 | body: Box2D.Body;
498 | fixture: box2d.b2Fixture;
499 | }
500 |
501 |
502 | class RaycastHit extends AABBHit {
503 | point: Phaser.Point;
504 | normal: Phaser.Point;
505 | }
506 | }
507 | }
508 | }
509 |
--------------------------------------------------------------------------------
/src/types/pixi.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for PIXI with Phaser Deviations.
2 |
3 | declare module PIXI {
4 |
5 | export var game: Phaser.Game;
6 | export var WEBGL_RENDERER: number;
7 | export var CANVAS_RENDERER: number;
8 | export var VERSION: string;
9 |
10 | export enum blendModes {
11 |
12 | NORMAL,
13 | ADD,
14 | MULTIPLY,
15 | SCREEN,
16 | OVERLAY,
17 | DARKEN,
18 | LIGHTEN,
19 | COLOR_DODGE,
20 | COLOR_BURN,
21 | HARD_LIGHT,
22 | SOFT_LIGHT,
23 | DIFFERENCE,
24 | EXCLUSION,
25 | HUE,
26 | SATURATION,
27 | COLOR,
28 | LUMINOSITY
29 |
30 | }
31 |
32 | export enum scaleModes {
33 |
34 | DEFAULT,
35 | LINEAR,
36 | NEAREST
37 |
38 | }
39 |
40 | export var defaultRenderOptions: PixiRendererOptions;
41 |
42 | export var INTERACTION_REQUENCY: number;
43 | export var AUTO_PREVENT_DEFAULT: boolean;
44 |
45 | export var PI_2: number;
46 | export var RAD_TO_DEG: number;
47 | export var DEG_TO_RAD: number;
48 |
49 | export var RETINA_PREFIX: string;
50 | export var identityMatrix: Matrix;
51 | export var glContexts: WebGLRenderingContext[];
52 | export var instances: any[];
53 |
54 | export var TextureSilentFail: boolean;
55 | export var BitmapText: { fonts: {} };
56 |
57 | export function isPowerOfTwo(width: number, height: number): boolean;
58 |
59 | export function rgb2hex(rgb: number[]): string;
60 | export function hex2rgb(hex: string): number[];
61 |
62 | export function autoDetectRenderer(width?: number, height?: number, options?: PixiRendererOptions): PixiRenderer;
63 | export function autoDetectRecommendedRenderer(width?: number, height?: number, options?: PixiRendererOptions): PixiRenderer;
64 |
65 | export function canUseNewCanvasBlendModes(): boolean;
66 | export function getNextPowerOfTwo(value: number): number;
67 |
68 | export function AjaxRequest(): XMLHttpRequest;
69 |
70 | export function CompileFragmentShader(gl: WebGLRenderingContext, shaderSrc: string[]): any;
71 | export function CompileProgram(gl: WebGLRenderingContext, vertexSrc: string[], fragmentSrc: string[]): any;
72 |
73 |
74 | export interface IEventCallback {
75 | (e?: IEvent): void;
76 | }
77 |
78 | export interface IEvent {
79 | type: string;
80 | content: any;
81 | }
82 |
83 | export interface HitArea {
84 | contains(x: number, y: number): boolean;
85 | }
86 |
87 | export interface IInteractionDataCallback {
88 | (interactionData: InteractionData): void;
89 | }
90 |
91 | export interface PixiRenderer {
92 |
93 | autoResize: boolean;
94 | clearBeforeRender: boolean;
95 | height: number;
96 | resolution: number;
97 | transparent: boolean;
98 | type: number;
99 | view: HTMLCanvasElement;
100 | width: number;
101 |
102 | destroy(): void;
103 | render(stage: DisplayObjectContainer): void;
104 | resize(width: number, height: number): void;
105 |
106 | }
107 |
108 | export interface PixiRendererOptions {
109 |
110 | autoResize?: boolean;
111 | antialias?: boolean;
112 | clearBeforeRender?: boolean;
113 | preserveDrawingBuffer?: boolean;
114 | resolution?: number;
115 | transparent?: boolean;
116 | view?: HTMLCanvasElement;
117 |
118 | }
119 |
120 | export interface BitmapTextStyle {
121 |
122 | font?: string;
123 | align?: string;
124 | tint?: string;
125 |
126 | }
127 |
128 | export interface TextStyle {
129 |
130 | align?: string;
131 | dropShadow?: boolean;
132 | dropShadowColor?: string;
133 | dropShadowAngle?: number;
134 | dropShadowDistance?: number;
135 | fill?: string;
136 | font?: string;
137 | lineJoin?: string;
138 | stroke?: string;
139 | strokeThickness?: number;
140 | wordWrap?: boolean;
141 | wordWrapWidth?: number;
142 |
143 | }
144 |
145 | export interface Loader {
146 |
147 | load(): void;
148 |
149 | }
150 |
151 | export interface MaskData {
152 |
153 | alpha: number;
154 | worldTransform: number[];
155 |
156 | }
157 |
158 | export interface RenderSession {
159 |
160 | context: CanvasRenderingContext2D;
161 | maskManager: CanvasMaskManager;
162 | scaleMode: scaleModes;
163 | smoothProperty: string;
164 | roundPixels: boolean;
165 |
166 | }
167 |
168 | export interface ShaderAttribute {
169 | // TODO: Find signature of shader attributes
170 | }
171 |
172 | export interface FilterBlock {
173 |
174 | visible: boolean;
175 | renderable: boolean;
176 |
177 | }
178 |
179 | export class AbstractFilter {
180 |
181 | constructor(fragmentSrc: string | string[], uniforms: any);
182 |
183 | dirty: boolean;
184 | padding: number;
185 | uniforms: any;
186 | fragmentSrc: string | string[];
187 |
188 | apply(frameBuffer: WebGLFramebuffer): void;
189 | syncUniforms(): void;
190 |
191 | }
192 |
193 | export class AlphaMaskFilter extends AbstractFilter {
194 |
195 | constructor(texture: Texture);
196 |
197 | map: Texture;
198 |
199 | onTextureLoaded(): void;
200 |
201 | }
202 |
203 | export class AsciiFilter extends AbstractFilter {
204 |
205 | size: number;
206 |
207 | }
208 |
209 | export class AssetLoader implements Mixin {
210 |
211 | assetURLs: string[];
212 | crossorigin: boolean;
213 | loadersByType: { [key: string]: Loader };
214 |
215 | constructor(assetURLs: string[], crossorigin: boolean);
216 |
217 | listeners(eventName: string): Function[];
218 | emit(eventName: string, data?: any): boolean;
219 | dispatchEvent(eventName: string, data?: any): boolean;
220 | on(eventName: string, fn: Function): Function;
221 | addEventListener(eventName: string, fn: Function): Function;
222 | once(eventName: string, fn: Function): Function;
223 | off(eventName: string, fn: Function): Function;
224 | removeAllEventListeners(eventName: string): void;
225 |
226 | load(): void;
227 |
228 |
229 | }
230 |
231 | export class AtlasLoader implements Mixin {
232 |
233 | url: string;
234 | baseUrl: string;
235 | crossorigin: boolean;
236 | loaded: boolean;
237 |
238 | constructor(url: string, crossorigin: boolean);
239 |
240 | listeners(eventName: string): Function[];
241 | emit(eventName: string, data?: any): boolean;
242 | dispatchEvent(eventName: string, data?: any): boolean;
243 | on(eventName: string, fn: Function): Function;
244 | addEventListener(eventName: string, fn: Function): Function;
245 | once(eventName: string, fn: Function): Function;
246 | off(eventName: string, fn: Function): Function;
247 | removeAllEventListeners(eventName: string): void;
248 |
249 | load(): void;
250 |
251 | }
252 |
253 | export class BaseTexture implements Mixin {
254 |
255 | static fromCanvas(canvas: HTMLCanvasElement, scaleMode?: scaleModes): BaseTexture;
256 |
257 | constructor(source: HTMLImageElement, scaleMode: scaleModes);
258 | constructor(source: HTMLCanvasElement, scaleMode: scaleModes);
259 |
260 | height: number;
261 | hasLoaded: boolean;
262 | mipmap: boolean;
263 | premultipliedAlpha: boolean;
264 | resolution: number;
265 | scaleMode: scaleModes;
266 | skipRender: boolean;
267 | source: HTMLImageElement;
268 | width: number;
269 |
270 | listeners(eventName: string): Function[];
271 | emit(eventName: string, data?: any): boolean;
272 | dispatchEvent(eventName: string, data?: any): boolean;
273 | on(eventName: string, fn: Function): Function;
274 | addEventListener(eventName: string, fn: Function): Function;
275 | once(eventName: string, fn: Function): Function;
276 | off(eventName: string, fn: Function): Function;
277 | removeAllEventListeners(eventName: string): void;
278 | forceLoaded(width: number, height: number): void;
279 | destroy(): void;
280 | dirty(): void;
281 | unloadFromGPU(): void;
282 |
283 | }
284 |
285 | export class BitmapFontLoader implements Mixin {
286 |
287 | constructor(url: string, crossorigin: boolean);
288 |
289 | baseUrl: string;
290 | crossorigin: boolean;
291 | texture: Texture;
292 | url: string;
293 |
294 | listeners(eventName: string): Function[];
295 | emit(eventName: string, data?: any): boolean;
296 | dispatchEvent(eventName: string, data?: any): boolean;
297 | on(eventName: string, fn: Function): Function;
298 | addEventListener(eventName: string, fn: Function): Function;
299 | once(eventName: string, fn: Function): Function;
300 | off(eventName: string, fn: Function): Function;
301 | removeAllEventListeners(eventName: string): void;
302 |
303 | load(): void;
304 |
305 | }
306 |
307 | export class BlurFilter extends AbstractFilter {
308 |
309 | blur: number;
310 | blurX: number;
311 | blurY: number;
312 |
313 | }
314 |
315 | export class BlurXFilter extends AbstractFilter {
316 |
317 | blur: number;
318 |
319 | }
320 |
321 | export class BlurYFilter extends AbstractFilter {
322 |
323 | blur: number;
324 |
325 | }
326 |
327 | export class CanvasBuffer {
328 |
329 | constructor(width: number, height: number);
330 |
331 | canvas: HTMLCanvasElement;
332 | context: CanvasRenderingContext2D;
333 | height: number;
334 | width: number;
335 |
336 | destroy(): void;
337 | clear(): void;
338 | resize(width: number, height: number): void;
339 |
340 | }
341 |
342 | export class CanvasPool {
343 |
344 | static create(parent: HTMLElement, width?: number, height?: number): HTMLCanvasElement;
345 | static getFirst(): HTMLCanvasElement;
346 | static remove(parent: HTMLElement): void;
347 | static removeByCanvas(canvas: HTMLCanvasElement): HTMLCanvasElement;
348 | static getTotal(): number;
349 | static getFree(): number;
350 |
351 | }
352 |
353 | export class CanvasMaskManager {
354 |
355 | pushMask(maskData: MaskData, renderSession: RenderSession): void;
356 | popMask(renderSession: RenderSession): void;
357 |
358 | }
359 |
360 | export class CanvasRenderer implements PixiRenderer {
361 |
362 | constructor(game: Phaser.Game);
363 |
364 | game: Phaser.Game;
365 | type: number;
366 | resolution: number;
367 | clearBeforeRender: boolean;
368 | transparent: boolean;
369 | autoResize: boolean;
370 | width: number;
371 | height: number;
372 | view: HTMLCanvasElement;
373 | context: CanvasRenderingContext2D;
374 | refresh: boolean;
375 | count: number;
376 | maskManager: CanvasMaskManager;
377 | renderSession: RenderSession;
378 |
379 | render(stage: DisplayObjectContainer): void;
380 | resize(width: number, height: number): void;
381 | destroy(removeView?: boolean): void;
382 |
383 | }
384 |
385 | export class CanvasTinter {
386 |
387 | static getTintedTexture(sprite: Sprite, color: number): HTMLCanvasElement;
388 | static tintWithMultiply(texture: Texture, color: number, canvas: HTMLCanvasElement): void;
389 | static tintWithOverlay(texture: Texture, color: number, canvas: HTMLCanvasElement): void;
390 | static tintWithPerPixel(texture: Texture, color: number, canvas: HTMLCanvasElement): void;
391 |
392 | static canUseMultiply: boolean;
393 | static tintMethod: any;
394 |
395 | }
396 |
397 | export class Circle implements HitArea {
398 |
399 | constructor(x: number, y: number, radius: number);
400 |
401 | x: number;
402 | y: number;
403 | radius: number;
404 |
405 | clone(): Circle;
406 | contains(x: number, y: number): boolean;
407 | getBounds(): Rectangle;
408 |
409 | }
410 |
411 | export class ColorMatrixFilter extends AbstractFilter {
412 |
413 | constructor();
414 |
415 | matrix: number[];
416 |
417 | }
418 |
419 | export class ColorStepFilter extends AbstractFilter {
420 |
421 | step: number;
422 |
423 | }
424 |
425 | export class ConvolutionFilter extends AbstractFilter {
426 |
427 | constructor(matrix: number[], width: number, height: number);
428 |
429 | matrix: Matrix;
430 | width: number;
431 | height: number;
432 |
433 | }
434 |
435 | export class CrossHatchFilter extends AbstractFilter {
436 |
437 | blur: number;
438 |
439 | }
440 |
441 | export class DisplacementFilter extends AbstractFilter {
442 |
443 | constructor(texture: Texture);
444 |
445 | map: Texture;
446 | offset: Point;
447 | scale: Point;
448 |
449 | }
450 |
451 | export class DotScreenFilter extends AbstractFilter {
452 |
453 | angle: number;
454 | scale: Point;
455 |
456 | }
457 |
458 | export class DisplayObject {
459 |
460 | alpha: number;
461 | buttonMode: boolean;
462 | cacheAsBitmap: boolean;
463 | defaultCursor: string;
464 | filterArea: Rectangle;
465 | filters: AbstractFilter[];
466 | hitArea: HitArea;
467 | interactive: boolean;
468 | mask: Graphics;
469 | parent: DisplayObjectContainer;
470 | pivot: Point;
471 | position: Point;
472 | renderable: boolean;
473 | rotation: number;
474 | scale: Point;
475 | stage: DisplayObjectContainer;
476 | visible: boolean;
477 | worldAlpha: number;
478 | worldPosition: Point;
479 | worldScale: Point;
480 | worldTransform: Matrix;
481 | worldRotation: number;
482 | worldVisible: boolean;
483 | x: number;
484 | y: number;
485 |
486 | click(e: InteractionData): void;
487 | displayObjectUpdateTransform(parent?: DisplayObjectContainer): void;
488 | generateTexture(resolution?: number, scaleMode?: number, renderer?: PixiRenderer | number): RenderTexture;
489 | mousedown(e: InteractionData): void;
490 | mouseout(e: InteractionData): void;
491 | mouseover(e: InteractionData): void;
492 | mouseup(e: InteractionData): void;
493 | mousemove(e: InteractionData): void;
494 | mouseupoutside(e: InteractionData): void;
495 | rightclick(e: InteractionData): void;
496 | rightdown(e: InteractionData): void;
497 | rightup(e: InteractionData): void;
498 | rightupoutside(e: InteractionData): void;
499 | setStageReference(stage: DisplayObjectContainer): void;
500 | tap(e: InteractionData): void;
501 | toGlobal(position: Point): Point;
502 | toLocal(position: Point, from: DisplayObject): Point;
503 | touchend(e: InteractionData): void;
504 | touchendoutside(e: InteractionData): void;
505 | touchstart(e: InteractionData): void;
506 | touchmove(e: InteractionData): void;
507 | updateTransform(parent?: DisplayObjectContainer): void;
508 |
509 | }
510 |
511 | export class DisplayObjectContainer extends DisplayObject {
512 |
513 | constructor();
514 |
515 | children: DisplayObject[];
516 | height: number;
517 | width: number;
518 | ignoreChildInput: boolean;
519 |
520 | addChild(child: DisplayObject): DisplayObject;
521 | addChildAt(child: DisplayObject, index: number): DisplayObject;
522 | getBounds(targetCoordinateSpace?: DisplayObject | Matrix): Rectangle;
523 | getChildAt(index: number): DisplayObject;
524 | getChildIndex(child: DisplayObject): number;
525 | getLocalBounds(): Rectangle;
526 | removeChild(child: DisplayObject): DisplayObject;
527 | removeChildAt(index: number): DisplayObject;
528 | removeChildren(beginIndex?: number, endIndex?: number): DisplayObject[];
529 | removeStageReference(): void;
530 | setChildIndex(child: DisplayObject, index: number): void;
531 | swapChildren(child: DisplayObject, child2: DisplayObject): void;
532 | contains(child: DisplayObject): boolean;
533 |
534 | }
535 |
536 | export class Ellipse implements HitArea {
537 |
538 | constructor(x: number, y: number, width: number, height: number);
539 |
540 | x: number;
541 | y: number;
542 | width: number;
543 | height: number;
544 |
545 | clone(): Ellipse;
546 | contains(x: number, y: number): boolean;
547 | getBounds(): Rectangle;
548 |
549 | }
550 |
551 | export class Event {
552 |
553 | constructor(target: any, name: string, data: any);
554 |
555 | target: any;
556 | type: string;
557 | data: any;
558 | timeStamp: number;
559 |
560 | stopPropagation(): void;
561 | preventDefault(): void;
562 | stopImmediatePropagation(): void;
563 |
564 | }
565 |
566 | export class EventTarget {
567 |
568 | static mixin(obj: any): void;
569 |
570 | }
571 |
572 | export class FilterTexture {
573 |
574 | constructor(gl: WebGLRenderingContext, width: number, height: number, scaleMode: scaleModes);
575 |
576 | fragmentSrc: string[];
577 | frameBuffer: WebGLFramebuffer;
578 | gl: WebGLRenderingContext;
579 | program: WebGLProgram;
580 | scaleMode: number;
581 | texture: WebGLTexture;
582 |
583 | clear(): void;
584 | resize(width: number, height: number): void;
585 | destroy(): void;
586 |
587 | }
588 |
589 | export class GraphicsData {
590 |
591 | constructor(lineWidth?: number, lineColor?: number, lineAlpha?: number, fillColor?: number, fillAlpha?: number, fill?: boolean, shape?: any);
592 |
593 | lineWidth: number;
594 | lineColor: number;
595 | lineAlpha: number;
596 | fillColor: number;
597 | fillAlpha: number;
598 | fill: boolean;
599 | shape: any;
600 | type: number;
601 |
602 | }
603 |
604 | export class Graphics extends DisplayObjectContainer {
605 |
606 | static POLY: number;
607 | static RECT: number;
608 | static CIRC: number;
609 | static ELIP: number;
610 | static RREC: number;
611 |
612 | blendMode: number;
613 | boundsPadding: number;
614 | fillAlpha: number;
615 | isMask: boolean;
616 | lineWidth: number;
617 | lineColor: number;
618 | tint: number;
619 | worldAlpha: number;
620 |
621 | arc(cx: number, cy: number, radius: number, startAngle: number, endAngle: number, anticlockwise: boolean): Graphics;
622 | arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): Graphics;
623 | beginFill(color?: number, alpha?: number): Graphics;
624 | bezierCurveTo(cpX: number, cpY: number, cpX2: number, cpY2: number, toX: number, toY: number): Graphics;
625 | clear(): Graphics;
626 | destroyCachedSprite(): void;
627 | drawCircle(x: number, y: number, diameter: number): Graphics;
628 | drawEllipse(x: number, y: number, width: number, height: number): Graphics;
629 | drawPolygon(...path: any[]): Graphics;
630 | drawRect(x: number, y: number, width: number, height: number): Graphics;
631 | drawRoundedRect(x: number, y: number, width: number, height: number, radius: number): Graphics;
632 | drawShape(shape: Circle): GraphicsData;
633 | drawShape(shape: Rectangle): GraphicsData;
634 | drawShape(shape: Ellipse): GraphicsData;
635 | drawShape(shape: Polygon): GraphicsData;
636 | endFill(): Graphics;
637 | generateTexture(resolution?: number, scaleMode?: number, padding?: number): RenderTexture;
638 | lineStyle(lineWidth?: number, color?: number, alpha?: number): Graphics;
639 | lineTo(x: number, y: number): Graphics;
640 | moveTo(x: number, y: number): Graphics;
641 | quadraticCurveTo(cpX: number, cpY: number, toX: number, toY: number): Graphics;
642 |
643 | }
644 |
645 | export class GrayFilter extends AbstractFilter {
646 |
647 | gray: number;
648 |
649 | }
650 |
651 | export class ImageLoader implements Mixin {
652 |
653 | constructor(url: string, crossorigin?: boolean);
654 |
655 | texture: Texture;
656 |
657 | listeners(eventName: string): Function[];
658 | emit(eventName: string, data?: any): boolean;
659 | dispatchEvent(eventName: string, data?: any): boolean;
660 | on(eventName: string, fn: Function): Function;
661 | addEventListener(eventName: string, fn: Function): Function;
662 | once(eventName: string, fn: Function): Function;
663 | off(eventName: string, fn: Function): Function;
664 | removeAllEventListeners(eventName: string): void;
665 |
666 | load(): void;
667 | loadFramedSpriteSheet(frameWidth: number, frameHeight: number, textureName: string): void;
668 |
669 | }
670 |
671 | export class InteractionData {
672 |
673 | global: Point;
674 | target: Sprite;
675 | originalEvent: Event;
676 |
677 | getLocalPosition(displayObject: DisplayObject, point?: Point, globalPos?: Point): Point;
678 |
679 | }
680 |
681 | export class InteractionManager {
682 |
683 | currentCursorStyle: string;
684 | last: number;
685 | mouse: InteractionData;
686 | mouseOut: boolean;
687 | mouseoverEnabled: boolean;
688 | onMouseMove: Function;
689 | onMouseDown: Function;
690 | onMouseOut: Function;
691 | onMouseUp: Function;
692 | onTouchStart: Function;
693 | onTouchEnd: Function;
694 | onTouchMove: Function;
695 | pool: InteractionData[];
696 | resolution: number;
697 | stage: DisplayObjectContainer;
698 | touches: { [id: string]: InteractionData };
699 |
700 | constructor(stage: DisplayObjectContainer);
701 | }
702 |
703 | export class InvertFilter extends AbstractFilter {
704 |
705 | invert: number;
706 |
707 | }
708 |
709 | export class JsonLoader implements Mixin {
710 |
711 | constructor(url: string, crossorigin?: boolean);
712 |
713 | baseUrl: string;
714 | crossorigin: boolean;
715 | loaded: boolean;
716 | url: string;
717 |
718 | listeners(eventName: string): Function[];
719 | emit(eventName: string, data?: any): boolean;
720 | dispatchEvent(eventName: string, data?: any): boolean;
721 | on(eventName: string, fn: Function): Function;
722 | addEventListener(eventName: string, fn: Function): Function;
723 | once(eventName: string, fn: Function): Function;
724 | off(eventName: string, fn: Function): Function;
725 | removeAllEventListeners(eventName: string): void;
726 |
727 | load(): void;
728 |
729 | }
730 |
731 | export class Matrix {
732 |
733 | a: number;
734 | b: number;
735 | c: number;
736 | d: number;
737 | tx: number;
738 | ty: number;
739 |
740 | append(matrix: Matrix): Matrix;
741 | apply(pos: Point, newPos: Point): Point;
742 | applyInverse(pos: Point, newPos: Point): Point;
743 | determineMatrixArrayType(): number[];
744 | identity(): Matrix;
745 | rotate(angle: number): Matrix;
746 | fromArray(array: number[]): void;
747 | translate(x: number, y: number): Matrix;
748 | toArray(transpose: boolean): number[];
749 | scale(x: number, y: number): Matrix;
750 |
751 | }
752 |
753 | export interface Mixin {
754 |
755 | listeners(eventName: string): Function[];
756 | emit(eventName: string, data?: any): boolean;
757 | dispatchEvent(eventName: string, data?: any): boolean;
758 | on(eventName: string, fn: Function): Function;
759 | addEventListener(eventName: string, fn: Function): Function;
760 | once(eventName: string, fn: Function): Function;
761 | off(eventName: string, fn: Function): Function;
762 | removeAllEventListeners(eventName: string): void;
763 |
764 | }
765 |
766 | export class NoiseFilter extends AbstractFilter {
767 |
768 | noise: number;
769 |
770 | }
771 |
772 | export class NormalMapFilter extends AbstractFilter {
773 |
774 | map: Texture;
775 | offset: Point;
776 | scale: Point;
777 |
778 | }
779 |
780 | export class PixelateFilter extends AbstractFilter {
781 |
782 | size: number;
783 |
784 | }
785 |
786 | export interface IPixiShader {
787 |
788 | fragmentSrc: string[];
789 | gl: WebGLRenderingContext;
790 | program: WebGLProgram;
791 | vertexSrc: string[];
792 |
793 | destroy(): void;
794 | init(): void;
795 |
796 | }
797 |
798 | export class PixiShader implements IPixiShader {
799 |
800 | constructor(gl: WebGLRenderingContext);
801 |
802 | attributes: ShaderAttribute[];
803 | defaultVertexSrc: string[];
804 | dirty: boolean;
805 | firstRun: boolean;
806 | textureCount: number;
807 | fragmentSrc: string[];
808 | gl: WebGLRenderingContext;
809 | program: WebGLProgram;
810 | vertexSrc: string[];
811 |
812 | initSampler2D(): void;
813 | initUniforms(): void;
814 | syncUniforms(): void;
815 |
816 | destroy(): void;
817 | init(): void;
818 |
819 | }
820 |
821 | export class PixiFastShader implements IPixiShader {
822 |
823 | constructor(gl: WebGLRenderingContext);
824 |
825 | textureCount: number;
826 | fragmentSrc: string[];
827 | gl: WebGLRenderingContext;
828 | program: WebGLProgram;
829 | vertexSrc: string[];
830 |
831 | destroy(): void;
832 | init(): void;
833 |
834 | }
835 |
836 | export class PrimitiveShader implements IPixiShader {
837 |
838 | constructor(gl: WebGLRenderingContext);
839 | fragmentSrc: string[];
840 | gl: WebGLRenderingContext;
841 | program: WebGLProgram;
842 | vertexSrc: string[];
843 |
844 | destroy(): void;
845 | init(): void;
846 |
847 | }
848 |
849 | export class ComplexPrimitiveShader implements IPixiShader {
850 |
851 | constructor(gl: WebGLRenderingContext);
852 | fragmentSrc: string[];
853 | gl: WebGLRenderingContext;
854 | program: WebGLProgram;
855 | vertexSrc: string[];
856 |
857 | destroy(): void;
858 | init(): void;
859 |
860 | }
861 |
862 | export class StripShader implements IPixiShader {
863 |
864 | constructor(gl: WebGLRenderingContext);
865 | fragmentSrc: string[];
866 | gl: WebGLRenderingContext;
867 | program: WebGLProgram;
868 | vertexSrc: string[];
869 |
870 | destroy(): void;
871 | init(): void;
872 |
873 | }
874 |
875 | export class Point {
876 |
877 | constructor(x?: number, y?: number);
878 |
879 | x: number;
880 | y: number;
881 |
882 | clone(): Point;
883 | set(x: number, y: number): void;
884 |
885 | }
886 |
887 | export class Polygon implements HitArea {
888 |
889 | constructor(points: Point[]);
890 | constructor(points: number[]);
891 | constructor(...points: Point[]);
892 | constructor(...points: number[]);
893 |
894 | points: any[];
895 |
896 | clone(): Polygon;
897 | contains(x: number, y: number): boolean;
898 |
899 | }
900 |
901 | export class Rectangle implements HitArea {
902 |
903 | constructor(x?: number, y?: number, width?: number, height?: number);
904 |
905 | x: number;
906 | y: number;
907 | width: number;
908 | height: number;
909 |
910 | clone(): Rectangle;
911 | contains(x: number, y: number): boolean;
912 |
913 | }
914 |
915 | export class RGBSplitFilter extends AbstractFilter {
916 |
917 | red: Point;
918 | green: Point;
919 | blue: Point;
920 |
921 | }
922 |
923 | export class Rope extends Strip {
924 |
925 | points: Point[];
926 | vertices: number[];
927 |
928 | constructor(texture: Texture, points: Point[]);
929 |
930 | refresh(): void;
931 | setTexture(texture: Texture): void;
932 |
933 | }
934 |
935 | export class RoundedRectangle implements HitArea {
936 |
937 | constructor(x?: number, y?: number, width?: number, height?: number, radius?: number);
938 |
939 | x: number;
940 | y: number;
941 | width: number;
942 | height: number;
943 | radius: number;
944 |
945 | clone(): RoundedRectangle;
946 | contains(x: number, y: number): boolean;
947 |
948 | }
949 |
950 | export class SepiaFilter extends AbstractFilter {
951 |
952 | sepia: number;
953 |
954 | }
955 |
956 | export class SmartBlurFilter extends AbstractFilter {
957 |
958 | blur: number;
959 |
960 | }
961 |
962 | export class SpineLoader implements Mixin {
963 |
964 | url: string;
965 | crossorigin: boolean;
966 | loaded: boolean;
967 |
968 | constructor(url: string, crossOrigin: boolean);
969 |
970 | listeners(eventName: string): Function[];
971 | emit(eventName: string, data?: any): boolean;
972 | dispatchEvent(eventName: string, data?: any): boolean;
973 | on(eventName: string, fn: Function): Function;
974 | addEventListener(eventName: string, fn: Function): Function;
975 | once(eventName: string, fn: Function): Function;
976 | off(eventName: string, fn: Function): Function;
977 | removeAllEventListeners(eventName: string): void;
978 |
979 | load(): void;
980 |
981 | }
982 |
983 | export class SpineTextureLoader {
984 |
985 | constructor(basePath: string, crossorigin: boolean);
986 |
987 | load(page: AtlasPage, file: string): void;
988 | unload(texture: BaseTexture): void;
989 |
990 | }
991 |
992 | export class Sprite extends DisplayObjectContainer {
993 |
994 | constructor(texture: Texture);
995 |
996 | anchor: Point;
997 | blendMode: blendModes;
998 | exists: boolean;
999 | shader: IPixiShader;
1000 | texture: Texture;
1001 | tint: number;
1002 |
1003 | setTexture(texture: Texture, destroyBase?: boolean): void;
1004 |
1005 | }
1006 |
1007 | export class SpriteBatch extends DisplayObjectContainer {
1008 |
1009 | constructor(texture?: Texture);
1010 |
1011 | ready: boolean;
1012 | textureThing: Texture;
1013 |
1014 | initWebGL(gl: WebGLRenderingContext): void;
1015 |
1016 | }
1017 |
1018 | export class SpriteSheetLoader implements Mixin {
1019 |
1020 | constructor(url: string, crossorigin?: boolean);
1021 |
1022 | baseUrl: string;
1023 | crossorigin: boolean;
1024 | frames: any;
1025 | texture: Texture;
1026 | url: string;
1027 |
1028 | listeners(eventName: string): Function[];
1029 | emit(eventName: string, data?: any): boolean;
1030 | dispatchEvent(eventName: string, data?: any): boolean;
1031 | on(eventName: string, fn: Function): Function;
1032 | addEventListener(eventName: string, fn: Function): Function;
1033 | once(eventName: string, fn: Function): Function;
1034 | off(eventName: string, fn: Function): Function;
1035 | removeAllEventListeners(eventName: string): void;
1036 |
1037 | load(): void;
1038 |
1039 | }
1040 |
1041 | export class Strip extends DisplayObjectContainer {
1042 |
1043 | static DrawModes: {
1044 |
1045 | TRIANGLE_STRIP: number;
1046 | TRIANGLES: number;
1047 |
1048 | };
1049 |
1050 | constructor(texture: Texture);
1051 |
1052 | blendMode: number;
1053 | colors: number[];
1054 | dirty: boolean;
1055 | indices: number[];
1056 | canvasPadding: number;
1057 | texture: Texture;
1058 | uvs: number[];
1059 | vertices: number[];
1060 |
1061 | getBounds(matrix?: Matrix): Rectangle;
1062 |
1063 | }
1064 |
1065 | export class Texture implements Mixin {
1066 |
1067 | static emptyTexture: Texture;
1068 |
1069 | static fromCanvas(canvas: HTMLCanvasElement, scaleMode?: scaleModes): Texture;
1070 |
1071 | constructor(baseTexture: BaseTexture, frame?: Rectangle, crop?: Rectangle, trim?: Rectangle);
1072 |
1073 | baseTexture: BaseTexture;
1074 | crop: Rectangle;
1075 | frame: Rectangle;
1076 | height: number;
1077 | noFrame: boolean;
1078 | requiresUpdate: boolean;
1079 | trim: Point;
1080 | width: number;
1081 | scope: any;
1082 | valid: boolean;
1083 |
1084 | listeners(eventName: string): Function[];
1085 | emit(eventName: string, data?: any): boolean;
1086 | dispatchEvent(eventName: string, data?: any): boolean;
1087 | on(eventName: string, fn: Function): Function;
1088 | addEventListener(eventName: string, fn: Function): Function;
1089 | once(eventName: string, fn: Function): Function;
1090 | off(eventName: string, fn: Function): Function;
1091 | removeAllEventListeners(eventName: string): void;
1092 |
1093 | destroy(destroyBase: boolean): void;
1094 | setFrame(frame: Rectangle): void;
1095 |
1096 | }
1097 |
1098 | export class TilingSprite extends Sprite {
1099 |
1100 | constructor(texture: Texture, width: number, height: number);
1101 |
1102 | canvasBuffer: PIXI.CanvasBuffer;
1103 | blendMode: number;
1104 | refreshTexture: boolean;
1105 | texture: Texture;
1106 | textureDebug: boolean;
1107 | tint: number;
1108 | tilePosition: Point;
1109 | tilePattern: PIXI.Texture;
1110 | tileScale: Point;
1111 | tileScaleOffset: Point;
1112 |
1113 | destroy(): void;
1114 | generateTilingTexture(forcePowerOfTwo?: boolean): void;
1115 | setTexture(texture: Texture): void;
1116 |
1117 | }
1118 |
1119 | export class TiltShiftFilter extends AbstractFilter {
1120 |
1121 | blur: number;
1122 | gradientBlur: number;
1123 | start: number;
1124 | end: number;
1125 |
1126 | }
1127 |
1128 | export class TiltShiftXFilter extends AbstractFilter {
1129 |
1130 | blur: number;
1131 | gradientBlur: number;
1132 | start: number;
1133 | end: number;
1134 |
1135 | updateDelta(): void;
1136 |
1137 | }
1138 |
1139 | export class TiltShiftYFilter extends AbstractFilter {
1140 |
1141 | blur: number;
1142 | gradientBlur: number;
1143 | start: number;
1144 | end: number;
1145 |
1146 | updateDelta(): void;
1147 |
1148 | }
1149 |
1150 | export class TwistFilter extends AbstractFilter {
1151 |
1152 | angle: number;
1153 | offset: Point;
1154 | radius: number;
1155 |
1156 | }
1157 |
1158 | export class VideoTexture extends BaseTexture {
1159 |
1160 | static baseTextureFromVideo(video: HTMLVideoElement, scaleMode: number): BaseTexture;
1161 | static textureFromVideo(video: HTMLVideoElement, scaleMode: number): Texture;
1162 | static fromUrl(videoSrc: string, scaleMode?: number, autoPlay?: boolean, type?: string, loop?: boolean): Texture;
1163 |
1164 | controls: boolean;
1165 | autoUpdate: boolean;
1166 | type: string;
1167 |
1168 | changeSource(src: string, type: string, loop: boolean): void;
1169 | play(): void;
1170 | stop(): void;
1171 |
1172 | destroy(): void;
1173 | updateBound(): void;
1174 | onPlayStart: () => void;
1175 | onPlayStop: () => void;
1176 | onCanPlay: (event: any) => void;
1177 |
1178 | }
1179 |
1180 | export class WebGLBlendModeManager {
1181 |
1182 | currentBlendMode: number;
1183 |
1184 | destroy(): void;
1185 | setBlendMode(blendMode: number): boolean;
1186 | setContext(gl: WebGLRenderingContext): void;
1187 |
1188 | }
1189 |
1190 | export class WebGLFastSpriteBatch {
1191 |
1192 | constructor(gl: CanvasRenderingContext2D);
1193 |
1194 | currentBatchSize: number;
1195 | currentBaseTexture: BaseTexture;
1196 | currentBlendMode: number;
1197 | renderSession: RenderSession;
1198 | drawing: boolean;
1199 | indexBuffer: any;
1200 | indices: number[];
1201 | lastIndexCount: number;
1202 | matrix: Matrix;
1203 | maxSize: number;
1204 | shader: IPixiShader;
1205 | size: number;
1206 | vertexBuffer: any;
1207 | vertices: number[];
1208 | vertSize: number;
1209 |
1210 | end(): void;
1211 | begin(spriteBatch: SpriteBatch, renderSession: RenderSession): void;
1212 | destroy(removeView?: boolean): void;
1213 | flush(): void;
1214 | render(spriteBatch: SpriteBatch): void;
1215 | renderSprite(sprite: Sprite): void;
1216 | setContext(gl: WebGLRenderingContext): void;
1217 | start(): void;
1218 | stop(): void;
1219 |
1220 | }
1221 |
1222 | export class WebGLFilterManager {
1223 |
1224 | filterStack: AbstractFilter[];
1225 | transparent: boolean;
1226 | offsetX: number;
1227 | offsetY: number;
1228 |
1229 | applyFilterPass(filter: AbstractFilter, filterArea: Texture, width: number, height: number): void;
1230 | begin(renderSession: RenderSession, buffer: ArrayBuffer): void;
1231 | destroy(): void;
1232 | initShaderBuffers(): void;
1233 | popFilter(): void;
1234 | pushFilter(filterBlock: FilterBlock): void;
1235 | setContext(gl: WebGLRenderingContext): void;
1236 |
1237 | }
1238 |
1239 | export class WebGLGraphics {
1240 |
1241 | static graphicsDataPool: any[];
1242 |
1243 | static renderGraphics(graphics: Graphics, renderRession: RenderSession): void;
1244 | static updateGraphics(graphics: Graphics, gl: WebGLRenderingContext): void;
1245 | static switchMode(webGL: WebGLRenderingContext, type: number): any;
1246 | static buildRectangle(graphicsData: GraphicsData, webGLData: any): void;
1247 | static buildRoundedRectangle(graphicsData: GraphicsData, webGLData: any): void;
1248 | static quadraticBezierCurve(fromX: number, fromY: number, cpX: number, cpY: number, toX: number, toY: number): number[];
1249 | static buildCircle(graphicsData: GraphicsData, webGLData: any): void;
1250 | static buildLine(graphicsData: GraphicsData, webGLData: any): void;
1251 | static buildComplexPoly(graphicsData: GraphicsData, webGLData: any): void;
1252 | static buildPoly(graphicsData: GraphicsData, webGLData: any): boolean;
1253 |
1254 | reset(): void;
1255 | upload(): void;
1256 |
1257 | }
1258 |
1259 | export class WebGLGraphicsData {
1260 |
1261 | constructor(gl: WebGLRenderingContext);
1262 |
1263 | gl: WebGLRenderingContext;
1264 | glPoints: any[];
1265 | color: number[];
1266 | points: any[];
1267 | indices: any[];
1268 | buffer: WebGLBuffer;
1269 | indexBuffer: WebGLBuffer;
1270 | mode: number;
1271 | alpha: number;
1272 | dirty: boolean;
1273 |
1274 | reset(): void;
1275 | upload(): void;
1276 |
1277 | }
1278 |
1279 | export class WebGLMaskManager {
1280 |
1281 | destroy(): void;
1282 | popMask(renderSession: RenderSession): void;
1283 | pushMask(maskData: any[], renderSession: RenderSession): void;
1284 | setContext(gl: WebGLRenderingContext): void;
1285 |
1286 | }
1287 |
1288 | export class WebGLRenderer implements PixiRenderer {
1289 |
1290 | static createWebGLTexture(texture: Texture, gl: WebGLRenderingContext): void;
1291 |
1292 | constructor(game: Phaser.Game);
1293 |
1294 | game: Phaser.Game;
1295 | type: number;
1296 | resolution: number;
1297 | transparent: boolean;
1298 | autoResize: boolean;
1299 | preserveDrawingBuffer: boolean;
1300 | clearBeforeRender: boolean;
1301 | width: number;
1302 | height: number;
1303 | view: HTMLCanvasElement;
1304 | projection: Point;
1305 | offset: Point;
1306 | shaderManager: WebGLShaderManager;
1307 | spriteBatch: WebGLSpriteBatch;
1308 | maskManager: WebGLMaskManager;
1309 | filterManager: WebGLFilterManager;
1310 | stencilManager: WebGLStencilManager;
1311 | blendModeManager: WebGLBlendModeManager;
1312 | renderSession: RenderSession;
1313 |
1314 | initContext(): void;
1315 | render(stage: DisplayObjectContainer): void;
1316 | renderDisplayObject(displayObject: DisplayObject, projection: Point, buffer: WebGLBuffer): void;
1317 | resize(width: number, height: number): void;
1318 | updateTexture(texture: Texture): void;
1319 | destroy(): void;
1320 | mapBlendModes(): void;
1321 |
1322 | }
1323 |
1324 | export class WebGLShaderManager {
1325 |
1326 | maxAttibs: number;
1327 | attribState: any[];
1328 | stack: any[];
1329 | tempAttribState: any[];
1330 |
1331 | destroy(): void;
1332 | setAttribs(attribs: ShaderAttribute[]): void;
1333 | setContext(gl: WebGLRenderingContext): void;
1334 | setShader(shader: IPixiShader): boolean;
1335 |
1336 | }
1337 |
1338 | export class WebGLStencilManager {
1339 |
1340 | stencilStack: any[];
1341 | reverse: boolean;
1342 | count: number;
1343 |
1344 | bindGraphics(graphics: Graphics, webGLData: any[], renderSession: RenderSession): void;
1345 | destroy(): void;
1346 | popStencil(graphics: Graphics, webGLData: any[], renderSession: RenderSession): void;
1347 | pushStencil(graphics: Graphics, webGLData: any[], renderSession: RenderSession): void;
1348 | setContext(gl: WebGLRenderingContext): void;
1349 |
1350 | }
1351 |
1352 | export class WebGLSpriteBatch {
1353 |
1354 | blendModes: number[];
1355 | colors: number[];
1356 | currentBatchSize: number;
1357 | currentBaseTexture: Texture;
1358 | defaultShader: AbstractFilter;
1359 | dirty: boolean;
1360 | drawing: boolean;
1361 | indices: number[];
1362 | lastIndexCount: number;
1363 | positions: number[];
1364 | textures: Texture[];
1365 | shaders: IPixiShader[];
1366 | size: number;
1367 | sprites: any[];
1368 | vertices: number[];
1369 | vertSize: number;
1370 |
1371 | begin(renderSession: RenderSession): void;
1372 | destroy(): void;
1373 | end(): void;
1374 | flush(shader?: IPixiShader): void;
1375 | render(sprite: Sprite): void;
1376 | renderBatch(texture: Texture, size: number, startIndex: number): void;
1377 | renderTilingSprite(sprite: TilingSprite): void;
1378 | setBlendMode(blendMode: blendModes): void;
1379 | setContext(gl: WebGLRenderingContext): void;
1380 | start(): void;
1381 | stop(): void;
1382 |
1383 | }
1384 |
1385 | export class RenderTexture extends Texture {
1386 |
1387 | constructor(width?: number, height?: number, renderer?: PixiRenderer, scaleMode?: scaleModes, resolution?: number);
1388 |
1389 | frame: Rectangle;
1390 | baseTexture: BaseTexture;
1391 | renderer: PixiRenderer;
1392 | resolution: number;
1393 | valid: boolean;
1394 |
1395 | clear(): void;
1396 | getBase64(): string;
1397 | getCanvas(): HTMLCanvasElement;
1398 | getImage(): HTMLImageElement;
1399 | resize(width: number, height: number, updateBase: boolean): void;
1400 | render(displayObject: DisplayObject, matrix?: Matrix, clear?: boolean): void;
1401 |
1402 | }
1403 |
1404 | // SPINE
1405 |
1406 | export class BoneData {
1407 |
1408 | constructor(name: string, parent?: any);
1409 |
1410 | name: string;
1411 | parent: any;
1412 | length: number;
1413 | x: number;
1414 | y: number;
1415 | rotation: number;
1416 | scaleX: number;
1417 | scaleY: number;
1418 |
1419 | }
1420 |
1421 | export class SlotData {
1422 |
1423 | constructor(name: string, boneData: BoneData);
1424 |
1425 | name: string;
1426 | boneData: BoneData;
1427 | r: number;
1428 | g: number;
1429 | b: number;
1430 | a: number;
1431 | attachmentName: string;
1432 |
1433 | }
1434 |
1435 | export class Bone {
1436 |
1437 | constructor(boneData: BoneData, parent?: any);
1438 |
1439 | data: BoneData;
1440 | parent: any;
1441 | yDown: boolean;
1442 | x: number;
1443 | y: number;
1444 | rotation: number;
1445 | scaleX: number;
1446 | scaleY: number;
1447 | worldRotation: number;
1448 | worldScaleX: number;
1449 | worldScaleY: number;
1450 |
1451 | updateWorldTransform(flipX: boolean, flip: boolean): void;
1452 | setToSetupPose(): void;
1453 |
1454 | }
1455 |
1456 | export class Slot {
1457 |
1458 | constructor(slotData: SlotData, skeleton: Skeleton, bone: Bone);
1459 |
1460 | data: SlotData;
1461 | skeleton: Skeleton;
1462 | bone: Bone;
1463 | r: number;
1464 | g: number;
1465 | b: number;
1466 | a: number;
1467 | attachment: RegionAttachment;
1468 | setAttachment(attachment: RegionAttachment): void;
1469 | setAttachmentTime(time: number): void;
1470 | getAttachmentTime(): number;
1471 | setToSetupPose(): void;
1472 |
1473 | }
1474 |
1475 | export class Skin {
1476 |
1477 | constructor(name: string);
1478 |
1479 | name: string;
1480 | attachments: any;
1481 |
1482 | addAttachment(slotIndex: number, name: string, attachment: RegionAttachment): void;
1483 | getAttachment(slotIndex: number, name: string): void;
1484 |
1485 | }
1486 |
1487 | export class Animation {
1488 |
1489 | constructor(name: string, timelines: ISpineTimeline[], duration: number);
1490 |
1491 | name: string;
1492 | timelines: ISpineTimeline[];
1493 | duration: number;
1494 | apply(skeleton: Skeleton, time: number, loop: boolean): void;
1495 | min(skeleton: Skeleton, time: number, loop: boolean, alpha: number): void;
1496 |
1497 | }
1498 |
1499 | export class Curves {
1500 |
1501 | constructor(frameCount: number);
1502 |
1503 | curves: number[];
1504 |
1505 | setLinear(frameIndex: number): void;
1506 | setStepped(frameIndex: number): void;
1507 | setCurve(frameIndex: number, cx1: number, cy1: number, cx2: number, cy2: number): void;
1508 | getCurvePercent(frameIndex: number, percent: number): number;
1509 |
1510 | }
1511 |
1512 | export interface ISpineTimeline {
1513 |
1514 | curves: Curves;
1515 | frames: number[];
1516 |
1517 | getFrameCount(): number;
1518 | apply(skeleton: Skeleton, time: number, alpha: number): void;
1519 |
1520 | }
1521 |
1522 | export class RotateTimeline implements ISpineTimeline {
1523 |
1524 | constructor(frameCount: number);
1525 |
1526 | curves: Curves;
1527 | frames: number[];
1528 | boneIndex: number;
1529 |
1530 | getFrameCount(): number;
1531 | setFrame(frameIndex: number, time: number, angle: number): void;
1532 | apply(skeleton: Skeleton, time: number, alpha: number): void;
1533 |
1534 | }
1535 |
1536 | export class TranslateTimeline implements ISpineTimeline {
1537 |
1538 | constructor(frameCount: number);
1539 |
1540 | curves: Curves;
1541 | frames: number[];
1542 | boneIndex: number;
1543 |
1544 | getFrameCount(): number;
1545 | setFrame(frameIndex: number, time: number, x: number, y: number): void;
1546 | apply(skeleton: Skeleton, time: number, alpha: number): void;
1547 |
1548 | }
1549 |
1550 | export class ScaleTimeline implements ISpineTimeline {
1551 |
1552 | constructor(frameCount: number);
1553 |
1554 | curves: Curves;
1555 | frames: number[];
1556 | boneIndex: number;
1557 |
1558 | getFrameCount(): number;
1559 | setFrame(frameIndex: number, time: number, x: number, y: number): void;
1560 | apply(skeleton: Skeleton, time: number, alpha: number): void;
1561 |
1562 | }
1563 |
1564 | export class ColorTimeline implements ISpineTimeline {
1565 |
1566 | constructor(frameCount: number);
1567 |
1568 | curves: Curves;
1569 | frames: number[];
1570 | boneIndex: number;
1571 |
1572 | getFrameCount(): number;
1573 | setFrame(frameIndex: number, time: number, r: number, g: number, b: number, a: number): void;
1574 | apply(skeleton: Skeleton, time: number, alpha: number): void;
1575 |
1576 | }
1577 |
1578 | export class AttachmentTimeline implements ISpineTimeline {
1579 |
1580 | constructor(frameCount: number);
1581 |
1582 | curves: Curves;
1583 | frames: number[];
1584 | attachmentNames: string[];
1585 | slotIndex: number;
1586 |
1587 | getFrameCount(): number;
1588 | setFrame(frameIndex: number, time: number, attachmentName: string): void;
1589 | apply(skeleton: Skeleton, time: number, alpha: number): void;
1590 |
1591 | }
1592 |
1593 | export class SkeletonData {
1594 |
1595 | bones: Bone[];
1596 | slots: Slot[];
1597 | skins: Skin[];
1598 | animations: Animation[];
1599 | defaultSkin: Skin;
1600 |
1601 | findBone(boneName: string): Bone;
1602 | findBoneIndex(boneName: string): number;
1603 | findSlot(slotName: string): Slot;
1604 | findSlotIndex(slotName: string): number;
1605 | findSkin(skinName: string): Skin;
1606 | findAnimation(animationName: string): Animation;
1607 |
1608 | }
1609 |
1610 | export class Skeleton {
1611 |
1612 | constructor(skeletonData: SkeletonData);
1613 |
1614 | data: SkeletonData;
1615 | bones: Bone[];
1616 | slots: Slot[];
1617 | drawOrder: any[];
1618 | x: number;
1619 | y: number;
1620 | skin: Skin;
1621 | r: number;
1622 | g: number;
1623 | b: number;
1624 | a: number;
1625 | time: number;
1626 | flipX: boolean;
1627 | flipY: boolean;
1628 |
1629 | updateWorldTransform(): void;
1630 | setToSetupPose(): void;
1631 | setBonesToSetupPose(): void;
1632 | setSlotsToSetupPose(): void;
1633 | getRootBone(): Bone;
1634 | findBone(boneName: string): Bone;
1635 | fineBoneIndex(boneName: string): number;
1636 | findSlot(slotName: string): Slot;
1637 | findSlotIndex(slotName: string): number;
1638 | setSkinByName(skinName: string): void;
1639 | setSkin(newSkin: Skin): void;
1640 | getAttachmentBySlotName(slotName: string, attachmentName: string): RegionAttachment;
1641 | getAttachmentBySlotIndex(slotIndex: number, attachmentName: string): RegionAttachment;
1642 | setAttachment(slotName: string, attachmentName: string): void;
1643 | update(data: number): void;
1644 |
1645 | }
1646 |
1647 | export class RegionAttachment {
1648 |
1649 | offset: number[];
1650 | uvs: number[];
1651 | x: number;
1652 | y: number;
1653 | rotation: number;
1654 | scaleX: number;
1655 | scaleY: number;
1656 | width: number;
1657 | height: number;
1658 | rendererObject: any;
1659 | regionOffsetX: number;
1660 | regionOffsetY: number;
1661 | regionWidth: number;
1662 | regionHeight: number;
1663 | regionOriginalWidth: number;
1664 | regionOriginalHeight: number;
1665 |
1666 | setUVs(u: number, v: number, u2: number, v2: number, rotate: number): void;
1667 | updateOffset(): void;
1668 | computeVertices(x: number, y: number, bone: Bone, vertices: number[]): void;
1669 |
1670 | }
1671 |
1672 | export class AnimationStateData {
1673 |
1674 | constructor(skeletonData: SkeletonData);
1675 |
1676 | skeletonData: SkeletonData;
1677 | animationToMixTime: any;
1678 | defaultMix: number;
1679 |
1680 | setMixByName(fromName: string, toName: string, duration: number): void;
1681 | setMix(from: string, to: string): number;
1682 |
1683 | }
1684 |
1685 | export class AnimationState {
1686 |
1687 | constructor(stateData: any);
1688 |
1689 | animationSpeed: number;
1690 | current: any;
1691 | previous: any;
1692 | currentTime: number;
1693 | previousTime: number;
1694 | currentLoop: boolean;
1695 | previousLoop: boolean;
1696 | mixTime: number;
1697 | mixDuration: number;
1698 | queue: Animation[];
1699 |
1700 | update(delta: number): void;
1701 | apply(skeleton: any): void;
1702 | clearAnimation(): void;
1703 | setAnimation(animation: any, loop: boolean): void;
1704 | setAnimationByName(animationName: string, loop: boolean): void;
1705 | addAnimationByName(animationName: string, loop: boolean, delay: number): void;
1706 | addAnimation(animation: any, loop: boolean, delay: number): void;
1707 | isComplete(): number;
1708 |
1709 | }
1710 |
1711 | export class SkeletonJson {
1712 |
1713 | constructor(attachmentLoader: AtlasAttachmentLoader);
1714 |
1715 | attachmentLoader: AtlasAttachmentLoader;
1716 | scale: number;
1717 |
1718 | readSkeletonData(root: any): SkeletonData;
1719 | readAttachment(skin: Skin, name: string, map: any): RegionAttachment;
1720 | readAnimation(name: string, map: any, skeletonData: SkeletonData): void;
1721 | readCurve(timeline: ISpineTimeline, frameIndex: number, valueMap: any): void;
1722 | toColor(hexString: string, colorIndex: number): number;
1723 |
1724 | }
1725 |
1726 | export class Atlas {
1727 |
1728 | static FORMAT: {
1729 |
1730 | alpha: number;
1731 | intensity: number;
1732 | luminanceAlpha: number;
1733 | rgb565: number;
1734 | rgba4444: number;
1735 | rgb888: number;
1736 | rgba8888: number;
1737 |
1738 | };
1739 |
1740 | static TextureFilter: {
1741 |
1742 | nearest: number;
1743 | linear: number;
1744 | mipMap: number;
1745 | mipMapNearestNearest: number;
1746 | mipMapLinearNearest: number;
1747 | mipMapNearestLinear: number;
1748 | mipMapLinearLinear: number;
1749 |
1750 | };
1751 |
1752 | static textureWrap: {
1753 |
1754 | mirroredRepeat: number;
1755 | clampToEdge: number;
1756 | repeat: number;
1757 |
1758 | };
1759 |
1760 | constructor(atlasText: string, textureLoader: AtlasLoader);
1761 |
1762 | textureLoader: AtlasLoader;
1763 | pages: AtlasPage[];
1764 | regions: AtlasRegion[];
1765 |
1766 | findRegion(name: string): AtlasRegion;
1767 | dispose(): void;
1768 | updateUVs(page: AtlasPage): void;
1769 |
1770 | }
1771 |
1772 | export class AtlasPage {
1773 |
1774 | name: string;
1775 | format: number;
1776 | minFilter: number;
1777 | magFilter: number;
1778 | uWrap: number;
1779 | vWrap: number;
1780 | rendererObject: any;
1781 | width: number;
1782 | height: number;
1783 |
1784 | }
1785 |
1786 | export class AtlasRegion {
1787 |
1788 | page: AtlasPage;
1789 | name: string;
1790 | x: number;
1791 | y: number;
1792 | width: number;
1793 | height: number;
1794 | u: number;
1795 | v: number;
1796 | u2: number;
1797 | v2: number;
1798 | offsetX: number;
1799 | offsetY: number;
1800 | originalWidth: number;
1801 | originalHeight: number;
1802 | index: number;
1803 | rotate: boolean;
1804 | splits: any[];
1805 | pads: any[];
1806 |
1807 | }
1808 |
1809 | export class AtlasReader {
1810 |
1811 | constructor(text: string);
1812 |
1813 | lines: string[];
1814 | index: number;
1815 |
1816 | trim(value: string): string;
1817 | readLine(): string;
1818 | readValue(): string;
1819 | readTuple(tuple: number): number;
1820 |
1821 | }
1822 |
1823 | export class AtlasAttachmentLoader {
1824 |
1825 | constructor(atlas: Atlas);
1826 |
1827 | atlas: Atlas;
1828 |
1829 | newAttachment(skin: Skin, type: number, name: string): RegionAttachment;
1830 |
1831 | }
1832 |
1833 | export class Spine extends DisplayObjectContainer {
1834 |
1835 | constructor(url: string);
1836 |
1837 | autoUpdate: boolean;
1838 | spineData: any;
1839 | skeleton: Skeleton;
1840 | stateData: AnimationStateData;
1841 | state: AnimationState;
1842 | slotContainers: DisplayObjectContainer[];
1843 |
1844 | createSprite(slot: Slot, descriptor: { name: string }): Sprite[];
1845 | update(dt: number): void;
1846 |
1847 | }
1848 |
1849 | }
1850 |
1851 | declare function requestAnimFrame(callback: Function): void;
1852 |
1853 | declare module PIXI.PolyK {
1854 | export function Triangulate(p: number[]): number[];
1855 | }
1856 |
--------------------------------------------------------------------------------