Bejeweled
Introduction¶
Match3-like gameplay template.
- Author: Rex
- Template
Live demos¶
Usage¶
Install plugin¶
Load minify file¶
- Load rexBoard plugin (minify file) in preload stage
scene.load.scenePlugin('rexboardplugin', 'https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/dist/rexboardplugin.min.js', 'rexBoard', 'rexBoard'); scene.load.script('rexbejeweled', 'https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/dist/rexbejeweled.min.js');
- Add bejeweled object
var bejeweled = new rexbejeweled(scene, config);
Import template¶
- Install rex plugins from npm
npm i phaser3-rex-plugins
- Install rexBoard plugin in configuration of game
import BoardPlugin from 'phaser3-rex-plugins/plugins/board-plugin.js'; import Bejeweled from 'phaser3-rex-plugins/templates/bejeweled/Bejeweled.js'; var config = { // ... plugins: { scene: [{ key: 'rexBoard', plugin: BoardPlugin, mapping: 'rexBoard' }, // ... ] } // ... }; var game = new Phaser.Game(config);
- Add bejeweled object
var bejeweled = new Bejeweled(scene, config);
Create bejeweled object¶
var bejeweled = new Bejeweled(scene, {
// rexBoard: 'rexBoard',
board: {
grid: {
gridType: 'quadGrid',
x: 30,
y: 30 - 600,
cellWidth: 60,
cellHeight: 60,
},
width: 10,
height: 20 // Prepared rows: upper 10 rows
},
match: {
// wildcard: undefined
// dirMask: undefined
},
chess: {
// pick random symbol from array, or a callback to return symbol
symbols: [0, 1, 2, 3, 4, 5],
// symbols: function(board, tileX, tileY, excluded) { return symbol; }
// User-defined chess game object
create: function (board) {
// Create Game object (Shape, Image, or Sprite)
var scene = board.scene;
var gameObject = scene.add.sprite(0, 0, textureKey, frame);
// Initial 'symbol' value
gameObject.setData('symbol', undefined);
// Add data changed event of 'symbol` key
gameObject.data.events.on('changedata_symbol', function (gameObject, value, previousValue) {
// Change the appearance of game object via new symbol value
gameObject.setFrame(newFrame);
});
return gameObject;
},
// scope for callbacks
scope: undefined,
// moveTo behavior
moveTo: {
speed: 400
},
// tileZ: 1,
},
// mask: false,
select1Action: undefined,
select2Action: undefined,
swapAction: undefined,
undoSwapAction: undefined,
eliminatingAction: undefined,
fallingAction: undefined,
// input: true
})
Configurations
rexBoard
: Key of 'rexBoard' plugin. Default is'rexBoard'
.- Board properties
board.width
: Board width in tiles.board.height
: Board height in tiles.board.grid.x
,board.grid.y
: World position of tile (0, 0)board.grid.cellWidth
,board.grid.cellHeight
: The width/height of the cell, in pixels.
- Chess properties
chess.symbols
: An array of possible symbols, or a callback to return a symbol. See Generate symbolchess.create
,chess.scope
: Callback of creating chess object.chess.moveTo.speed
: Constant moving speed of chess, in pixel per-second.
- Custom actions
select1Action
: Custom select first chess Actionselect2Action
: Custom select second chess ActionswapAction
: Custon swap actionundoSwapAction
: Custon undo-swap actioneliminatingAction
: Custon eliminating actionfallingAction
: Custon falling action
- Touch input
input
: Settrue
to register default touch input logic.
- Mask
mask
:false
: No mask. Default behavior.true
: Mask invisible upper rows.- Create an internal layer
- Mask this internal layer.
Board height¶
Board is separated into two parts: upper and bottom
- Bottom : Visible N rows, to swap chess and run matching.
- Upper : Invisible N rows, chess in these rows will move down, to fill bottom rows.
For example, if amount of visible rows is 10
, board.height
should set to 20
.
Generate symbol¶
Symbols are declared in property chess.symbols
in a symbol array like [0, 1, 2, 3, 4, 5]
, or a callback to return a symbol. The callback also use chess.scope
as the scope.
function(board, tileX, tileY, excluded) {
return symbol
}
excluded
:undefined
or a symbol array. Don't return these symbols.
Create chess object¶
Return a game object from a callback.
function(board) {
// Create Game object (Image, Sprite, or Shape)
var scene = board.scene;
var gameObject = scene.add.sprite(0, 0, textureKey, frame);
// Initial 'symbol' value
gameObject.setData('symbol', undefined);
// Add data changed event of 'symbol` key
gameObject.data.events.on('changedata_symbol', function (gameObject, value, previousValue) {
// Change the appearance of game object via new symbol value
gameObject.setFrame(newFrame);
});
return gameObject;
}
Each chess has a symbol
value stored in 'symbol'
key in private data. Add data changed event of 'symbol'
key to change the appearance of game object via new symbol value.
States¶
graph TD
Start((Start)) --> Select1Start[select1-start]
subgraph Select 1 states
Select1Start --> |Input| Select1[select1]
end
Select1 --> select2Start[select2-start]
subgraph Select 2 states
select2Start --> |Input| select2[select2]
end
select2Start --> Select1Start
select2 --> Swap[swap]
Swap --> MatchStart[match-start]
subgraph Match states
MatchStart --> Match[match]
Match --> Eliminate[eliminate]
Match --> MatchEnd[match-end]
Eliminate --> Fall[fall]
Fall --> Fill[fill]
Fill --> Match
end
MatchEnd --> UndoSwap[undo-swap]
UndoSwap --> Select1Start
MatchEnd --> Select1Start
Select first chess¶
Fire 'select1'
event
bejeweled.on('select1', function(board, bejeweled) {
}, scope);
board
: Board object.bejeweled
: This bejeweled object.
Custom Select first chess Action¶
Default select action:
function (chess, board, bejeweled) {
// Do nothing
}
Select second chess¶
Fire 'select2'
event
bejeweled.on('select2', function(board, bejeweled) {
}, scope);
board
: Board object.bejeweled
: This bejeweled object.- Selected first chess :
var chess = bejeweled.getSelectedChess1();
- Selected first chess :
Custom Select second chess Action¶
Default select action: The same as Select first chess Action
Swap selected chess¶
Fire 'swap'
event
bejeweled.on('swap', function(selectedChess1, selectedChess2, board, bejeweled) {
}, scope);
board
: Board object.bejeweled
: This bejeweled object.
Custom Swap Action¶
Default swap action:
function (chess1, chess2, board, bejeweled) {
var tileXYZ1 = board.chessToTileXYZ(chess1);
var tileXYZ2 = board.chessToTileXYZ(chess2);
var tileX1 = tileXYZ1.x,
tileY1 = tileXYZ1.y,
tileX2 = tileXYZ2.x,
tileY2 = tileXYZ2.y,
tileZ = tileXYZ1.z;
// TileZ of chess1 and chess2 are the same, change tileZ of chess2 to a different value
board.moveChess(chess2, tileX2, tileY2, `#${tileZ}`, false);
// Move chess1 to tileXYZ2, chess2 to tileXYZ1
var moveTo1 = bejeweled.getChessMoveTo(chess1);
var moveTo2 = bejeweled.getChessMoveTo(chess2);
moveTo1.moveTo(tileX2, tileY2);
moveTo2.moveTo(tileX1, tileY1);
// Change tileZ of chess2 back
board.moveChess(chess2, tileX1, tileY1, tileZ, false);
if (moveTo1.isRunning) {
bejeweled.waitEvent(moveTo1, 'complete');
}
if (moveTo2.isRunning) {
bejeweled.waitEvent(moveTo2, 'complete');
}
};
bejeweled.getChessMoveTo(chess)
: Get moveTo behavior of a chess.bejeweled.waitEvent(moveTo, 'complete')
: Wait 'complete' event of this moveTo behavior.
Match start¶
Fire 'match-start'
event
bejeweled.on('match-start', function(board, bejeweled) {
}, scope);
board
: Board object.bejeweled
: This bejeweled object.
Match lines¶
Fire 'match'
event
bejeweled.on('match', function(lines, board, bejeweled) {
}, scope);
lines
: An array of matched lines, each line is a built-in Set object.- Length of each line (
lines[i].size
) could be 5, 4, or 3. lines[i].entries
: An array of chess (Game Object) in a matched line.- Get cross chess of two lines via
lineA.intersect(lineB)
. - All chess game objects in matched lines will be eliminated in next stage.
- Add/remove chess game object in a line.
- Add new line/remove a line in
lines
array to change the eliminated targets.
- Length of each line (
board
: Board object.- Get tile position
{x,y,z}
of a chess game object viavar tileXYZ = board.chessToTileXYZ(gameObject); //var tileXYZ = gameObject.rexChess.tileXYZ;
- Get chess game object of a tile position
{x,y,z}
viavar gameObject = board.tileXYZToChess(tileX, tileY, tileZ);
- Get array of neighbor chess of a chess game object via
var gameObjects = board.getNeighborChess(chess, null);
- Get tile position
bejeweled
: This bejeweled object.
Eliminating chess¶
Fire 'eliminate'
event
bejeweled.on('eliminate', function(chessArray, board, bejeweled) {
}, scope);
chessArray
: An array of chess (Game Object) to be eliminated.board
: Board objectbejeweled
: This bejeweled object.
Custom Eliminating Action¶
Default eliminating action:
function (chessArray, board, bejeweled) {
const duration = 500; //ms
for (var i = 0, cnt = chessArray.length; i < cnt; i++) {
var fade = FadeOutDestroy(chessArray[i], duration);
bejeweled.waitEvent(fade, 'complete');
}
}
bejeweled.waitEvent(fade, 'complete')
: Wait 'complete' event of this fade-out-destroy behavior.
Falling chess¶
Fire 'fall'
event
bejeweled.on('fall', function(board, bejeweled) {
}, scope);
board
: Board objectbejeweled
: This bejeweled object.
Custom Falling Action¶
Default falling action:
function (board, bejeweled) {
var tileZ = bejeweled.chessTileZ,
chess, moveTo;
for (var tileY = (board.height - 1); tileY >= 0; tileY--) { // bottom to top
for (var tileX = 0, cnt = board.width; tileX < cnt; tileX++) { // left to right
chess = board.tileXYZToChess(tileX, tileY, tileZ);
if (chess === null) {
continue;
}
moveTo = bejeweled.getChessMoveTo(chess);
do {
moveTo.moveToward(1);
} while (moveTo.lastMoveResult)
if (moveTo.isRunning) {
bejeweled.waitEvent(moveTo, 'complete');
}
}
}
}
bejeweled.getChessMoveTo(chess)
: Get moveTo behavior of a chess.bejeweled.waitEvent(moveTo, 'complete')
: Wait 'complete' event of this moveTo behavior.
Fill chess¶
Fire 'fill'
event
bejeweled.on('fill', function(board, bejeweled) {
}, scope);
board
: Board object.bejeweled
: This bejeweled object.
Match end¶
Fire 'match-end'
event
bejeweled.on('match-end', function(board, bejeweled) {
}, scope);
board
: Board object.bejeweled
: This bejeweled object.
Undo-swap selected chess¶
Fire 'undo-swap'
event
bejeweled.on('undo-swap', function(selectedChess1, selectedChess2, board, bejeweled) {
}, scope);
board
: Board object.bejeweled
: This bejeweled object.
Custom Undo-Swap Action¶
Default undo-swap action : Equal to Swap action
Start gameplay¶
bejeweled.start();
Input control¶
Default input¶
- Enable default input control
var bejeweled = new Bejeweled(scene, { // ... input: true });
- Enable/disable temporarily.
- Enable
bejeweled.setInputEnable();
- Disable
bejeweled.setInputEnable(false);
- Enable
Custom input¶
- Discard default input control
var bejeweled = new Bejeweled(scene, { // ... input: false });
- Add custom input logic like
scene.input .on('pointerdown', function (pointer) { var chess = bejeweled.worldXYToChess(pointer.worldX, pointer.worldY); if (chess) { bejeweled.selectChess1(chess); } }, scene) .on('pointermove', function (pointer) { if (!pointer.isDown) { return; } var chess = bejeweled.worldXYToChess(pointer.worldX, pointer.worldY); if (chess && (chess !== this.bejeweled.getSelectedChess1())) { bejeweled.selectChess2(chess); } }, scene);
- Invoke
bejeweled.selectChess1(chess)
, andbejeweled.selectChess2(chess)
under custom logic.
- Invoke
Helper methods
- Get chess via worldXY position
var chess = bejeweled.worldXYToChess(worldX, worldY);
- Get chess via tileXY position
var chess = bejeweled.tileXYToChess(tileX, tileY);
- Get neighbor chess via angle
var chess2 = bejeweled.getNeighborChessAtAngle(chess1, angle);
chess1
: Chess object, or tileXY position{x, y}
.angle
: Angle in radius.
- Get neighbor chess via direction
var chess2 = bejeweled.getNeighborChessAtDirection(chess1, direction);
chess1
: Chess object, or tileXY position{x, y}
.direction
: Number, or string number.0
~3
: Quad grid in 4 directions mode.0
~7
: Quad grid in 8 directions mode.0
~5
: Hexagon grid.
Data¶
- Get
var value = bejeweled.getData(key); var values = bejeweled.getData(keys); // keys: an array of keys var value = bejeweled.data.values[key];
- Set
bejeweled.setData(key, value); bejeweled.setData(obj); // obj: {key0:value0, key1:value1, ...} bejeweled.data.values[key] = value; bejeweled.data.values[key] += inc;
- Enable
bejeweled.setDataEnabled();
- Events :
- Set data evant
bejeweled.on('setdata', function(bejeweled, key, value){ /* ... */ });
- Change data event
bejeweled.on('changedata', function(bejeweled, key, value, previousValue){ /* ... */ });
bejeweled.on('changedata-' + key, function(bejeweled, value, previousValue){ /* ... */ });
- Set data evant
See data manager
Note
Ensure data manager is created before binding any data-changed events.