Introduction
This post introduces how to spin up a phaser.io game integrated with a Kintone Web Database.
There's no need to set up a node.js environment, to get an AWS serverless environment ready, or to install the latest .NET framework.
If you have a browser and a text editor, you can follow along easily.
And no, you won't be needing a credit card, so you can put that away.
What is Kintone?
Kintone is a cloud platform for teams with a visual web database builder. Kintone's REST APIs and JavaScript APIs enable further extensions to be built on top of the platform.
https://www.kintone.com/
What is Phaser.io?
Phaser is a free 2D game framework for making HTML5 games for desktop and mobile.
https://phaser.io/
Prerequisites
A Kintone Cloud Environment
Kintone is a cloud service that has flexible web database features.
We will be creating a web database on Kintone, and then building a phaser.io game on top of that.
You can obtain a Kintone environment by either applying for a free Kintone Developer License, or requesting for a free trial through Kintone.com. The former is more handy, as the developer license will be available to you indefinitely.
Phaser.io Files
In this example, we will be using the Phaser 2 library and an example game listed on their website, Invaders. I understand that Phaser 3 is available, but to be honest, I couldn't find any good game examples that use Phaser 3.
The Phaser Version 2 Library
This library can be obtained from the below page.
https://phaser.io/download/release/2.13.3
Download the js file to your local computer.
The Invaders Game Example Code
This code is available on the below page.
https://phaser.io/examples/v2/games/invaders#download
Save the zip file on to your local computer and extract the phaser-examples-master folder.
Running the Invaders Game on Kintone
Follow these 5 steps to start running the Invaders game on Kintone
1. Create a Kintone App
Web databases in Kintone are called "Apps".
Once you log in, click on the + sign on the Apps widget to start creating a new App. Select "Create App from Scratch", and give a name to your App.
On the form editor, drag and drop 2 number fields into the form. Name them "Scale" and "Health", and also set their field codes as "Scale" and "Health".
Save the form, and click on the blue Activate App button.
Your web database is now ready, and you will be directed to a page that holds a list of your data. Except that you don't have any data yet, so it will contain no data.
Which is where we move on to our next step.
2. Input Some Data
On this List view page, click on the + button to start adding data to the App.
You'll notice that the input form is the form you created in the previous step. Let's place in the value 0.2 for the Scale field, and the value 5 for the Health field. Click on Save to save this input data.
Click on the + button again to input some new data. Let's place in 1 and 10 for Scale and Health.
Repeat this process again, and place in 0.7 and 2 for Scale and Health.
OK, once we are done here, click on the name of your App to navigate to the List view. Previously, we saw this page had not data. Now that you've put new data inside, it should now look a bit more lively.
We will be utilizing this data in a later step.
3. Create a Custom View
Access the App's setting page by clicking the cog wheel.
The view tab allows you to set new views by limiting the fields you want to see, and by setting filter conditions. Kintone also allows a "Calendar view and" a "Custom view".
In this example, we will be using a Custom view, which is a view defined by HTML elements.
Click on the + button to add a new view, and select "Custom view". In the "HTML Code" option, insert the following html:
<div id="phaser-example"></div>
Click Save, and then the Update App button to apply these new settings.
4. Make Edits to the Invaders JavaScript File
We need to modify the invaders.js file before applying it to the Kintone App.
Open up the invaders file in your local editor. This file can be found in the phaser-examples-master folder under examples > games.
Update the preload() Function
By default, the Invaders code is loading images in this method by stating a local path. As we are activating this game on the browser, we need to change these paths to a valid path. Unfortunately, Kintone doesn't have a stable place to host image files (I hope this gets updated soon!), so upload the images onto an image hosting service such as https://imgur.com and reference these images in the preload() function:
game.load.image('bullet','{path to bullet.png}');
game.load.image('enemyBullet', '{path to enemy-bullet.png}');
game.load.spritesheet('invader', '{path to invader32x32x4.png}', 32, 32);
game.load.image('ship', '{path to player.png}');
game.load.spritesheet('kaboom', '{path to explode.png}', 128, 128);
game.load.image('starfield', '{path to starfield.png}');
//game.load.image('background', '{path to background2.png}'); <-- this file is not used
If you are using imgur, the link should be in the format of https://i.imgur.com/{randomstring}.png
The name and locations of the images within the downloaded folder may be a bit confusing - use the below table as reference:
Image variable | Image | Location |
---|---|---|
bullet | assets/games/invaders/bullet.png | |
enemyBullet | assets/games/invaders/enemy-bullet.png | |
invader | assets/games/invaders/invader32x32x4.png | |
ship | assets/games/invaders/player.png | |
kaboom | assets/games/invaders/explode.png | |
starfield | assets/games/invaders/starfield.png |
Update the Phaser.Game method
State "Phaser.CANVAS" for the third parameter of the Phaser.Game method so that images can be loaded and used from an external server.
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
Update the restart() Function
This Invaders example doesn't reset the score when you die and restart the game. It's not a large matter, but it was sort of bugging me, so add the following code at the end of the restart() function in the invaders.js file so that the score resets to 0 when you restart your Invaders game:
score = 0;
scoreText.text = scoreString + score;
5. Add JavaScript files to Your Kintone App
Now this is the final step for getting the Invaders file to work on top of Kintone.
Access the App's settings page by clicking on the cog wheel. Click on the "App Settings" tab, and select the "JavaScript and CSS Customization" settings. This page allows you to upload JavaScript and CSS files that are to be run when pages of the Kintone App run.
Under the "Upload JavaScript for PC" settings, click on "Upload file", and upload the phaser.js library, and the Invaders file that we've been working on. Make sure that the phaser.js library is located above the Invaders file, as Kintone will read these files in order from the top, and the Invaders file will be using methods that exist within the phaser.js library.
Once uploaded, click on Save, and Update changes to apply these new changes to the App.
You should be navigated to the Custom view page, where the Invaders game should load.
Use the arrow keys to move the player's ship, and the spacebar to shoot bullets! Pew pew!
Further Configurations to the Invaders Game
Before integrating the game with the data in our Kintone database, we'll make some further updates to the code.
Scaling the Alien Size
The createAliens() function contains the code for, well, creating the Aliens.
for (var y = 0; y < 4; y++)
{
for (var x = 0; x < 10; x++)
{
var alien = aliens.create(x * 48, y * 50, 'invader');
alien.anchor.setTo(0.5, 0.5);
alien.animations.add('fly', [ 0, 1, 2, 3 ], 20, true);
alien.play('fly');
alien.body.moves = false;
}
}
Scale the alien size by adjusting the scale property of the aliens:
for (var y = 0; y < 4; y++)
{
for (var x = 0; x < 10; x++)
{
var alien = aliens.create(x * 48, y * 50, 'invader');
alien.anchor.setTo(0.5, 0.5);
alien.animations.add('fly', [ 0, 1, 2, 3 ], 20, true);
alien.play('fly');
alien.body.moves = false;
alien.scale.x = 0.2; //<---
alien.scale.y = 0.2; //<---
}
}
This should make the aliens 1/5 of the default size.
Adding HP to the aliens
Aliens in this Invaders game die with just one hit of the laser. This is due to alien.kill() method being called within the collisionHandler() function. Phaser has a health component (Phaser.Component.Health) that adds an HP component to the game's characters, so that the kill method is called when their HP reaches or goes below 0.
To configure the aliens to have HP, first replace the alien.kill() method with alien.damage() method within the collisionHandler() function:
// When a bullet hits an alien we kill them both
bullet.kill();
//alien.kill(); //<---
alien.damage(1); //<---
Next, configure the aliens' health parameters in the createAliens() function:
for (var y = 0; y < 4; y++)
{
for (var x = 0; x < 10; x++)
{
var alien = aliens.create(x * 48, y * 50, 'invader');
alien.anchor.setTo(0.5, 0.5);
alien.animations.add('fly', [ 0, 1, 2, 3 ], 20, true);
alien.play('fly');
alien.body.moves = false;
alien.scale.x = 0.2;
alien.scale.y = 0.2;
alien.health = 5; //<---
}
}
With this, aliens will start off with an HP of 5, which will be reduced by the integer stated in alien.damage() every time the player's bullet hits them. When the alien's HP reaches 0 or below, the alien's kill method will be called.
Integrating Databases with the Invaders Game
OK so now that we've got our Invaders game running on the browser on top of Kintone, we'll get right to the question - why are we using a Kintone database to do this?
This is because we want to relate the data inside the database with the Invaders game that we are playing.
Let's add some final touches.
Add an Immediate Function and a Kintone Event
As a best practice to writing code on Kintone, we will wrap the current code in an immediate function, and also set a Kintone List View event. This will ensure that the code will run only when the record list view (including the custom view) is displayed.
(function () {
"use strict";
kintone.events.on('app.record.index.show', function (event) {
/////////////////////////////////////
// The code we've written so far //
/////////////////////////////////////
});
})();
When using "use strict", undeclared variables cause errors.
For some reason, enemyBullets, live and bullet are not declared in the original code, so declare them in the list of variables under the preload() function:
var player;
var aliens;
var bullets;
var bulletTime = 0;
var cursors;
var fireButton;
var explosions;
var starfield;
var score = 0;
var scoreString = '';
var scoreText;
var lives;
var enemyBullet;
var firingTimer = 0;
var stateText;
var livingEnemies = [];
var enemyBullets; //<---
var live; //<---
var bullet; //<---
Set the Code to Run Only on the Custom View
The Invaders game code will run in any view since we are currently using Kintone's Record List View event.
To ensure that the game code will only run when we are in the Custom view, add the following:
(function () {
"use strict";
kintone.events.on('app.record.index.show', function (event) {
if (event.viewType != "custom") {return;} // <---
Update the createAliens() Function
Replace the double loop that created the aliens to the below code.
for (var i=0; i<event.records.length;i++)
{
var alien = aliens.create(i * 48, 50, 'invader');
alien.anchor.setTo(0.5, 0.5);
alien.animations.add('fly', [ 0, 1, 2, 3 ], 20, true);
alien.play('fly');
alien.body.moves = false;
alien.scale.x = event.records[i].Scale.value;
alien.scale.y = event.records[i].Scale.value;
alien.health = event.records[i].Health.value;
}
The event variable is an object made available by Kintone when the Record List event was triggered. It includes data of the Record List, including an array of record data. As we have set the field codes for the two number fields to be Scale and Health, the values for these fields can be found in each content of the array. For example, event.records[0].Scale.value will have the numerical value stored in the Scale field of the 1st record.
The code above will create multiple aliens equal to the number of records in the record list (taken from event.records.length). Also, the size and health changed from being predefined numbers to values from the Kintone database records.
Update the collisionHandler() Function
The explosion animation that is displayed when the player's bullets hit the enemies are a bit off when the aliens are scaled down/up.
To fix this bug, the explosion.reset(alien.body.x, alien.body.y); method in the collisionHandler() function needs to be altered:
explosion.reset(alien.body.center.x, alien.body.center.y);
Save the File and Re-Upload It to the Kintone App
Now that the code is further altered, save your invaders.js file, access the JavaScript and CSS Customization settings of the Kintone App, and replace the old file with the latest saved file.
Click Save, and Update App to apply the changes.
Try out the updated game in your Custom view
Summary
This post went through how to set up an Invaders game related to a web database, just using the browser and a Kintone cloud environment. By doing this, users who are not able to code can join the game development process by updating the Kintone database properties and adding in new data, that will be reflected upon the Invaders file.
Feel free to copy the code and test it out on your environment - I will be happy to see enhanced versions of the example code in this post!
The resulting invaders code used
(function () {
"use strict";
kintone.events.on('app.record.index.show', function (event) {
if (event.viewType != "custom") {return;}
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
function preload() {
game.load.image('bullet','{path to image}');
game.load.image('enemyBullet', '{path to image}');
game.load.spritesheet('invader', '{path to image}', 32, 32);
game.load.image('ship', '{path to image}');
game.load.spritesheet('kaboom', '{path to image}', 128, 128);
game.load.image('starfield', '{path to image}');
game.load.image('background', '{path to image}');
}
var player;
var aliens;
var bullets;
var bulletTime = 0;
var cursors;
var fireButton;
var explosions;
var starfield;
var score = 0;
var scoreString = '';
var scoreText;
var lives;
var enemyBullet;
var firingTimer = 0;
var stateText;
var livingEnemies = [];
var enemyBullets;
var live;
var bullet;
function create() {
game.physics.startSystem(Phaser.Physics.ARCADE);
// The scrolling starfield background
starfield = game.add.tileSprite(0, 0, 800, 600, 'starfield');
// Our bullet group
bullets = game.add.group();
bullets.enableBody = true;
bullets.physicsBodyType = Phaser.Physics.ARCADE;
bullets.createMultiple(30, 'bullet');
bullets.setAll('anchor.x', 0.5);
bullets.setAll('anchor.y', 1);
bullets.setAll('outOfBoundsKill', true);
bullets.setAll('checkWorldBounds', true);
// The enemy's bullets
enemyBullets = game.add.group();
enemyBullets.enableBody = true;
enemyBullets.physicsBodyType = Phaser.Physics.ARCADE;
enemyBullets.createMultiple(30, 'enemyBullet');
enemyBullets.setAll('anchor.x', 0.5);
enemyBullets.setAll('anchor.y', 1);
enemyBullets.setAll('outOfBoundsKill', true);
enemyBullets.setAll('checkWorldBounds', true);
// The hero!
player = game.add.sprite(400, 500, 'ship');
player.anchor.setTo(0.5, 0.5);
game.physics.enable(player, Phaser.Physics.ARCADE);
// The baddies!
aliens = game.add.group();
aliens.enableBody = true;
aliens.physicsBodyType = Phaser.Physics.ARCADE;
createAliens();
// The score
scoreString = 'Score : ';
scoreText = game.add.text(10, 10, scoreString + score, { font: '34px Arial', fill: '#fff' });
// Lives
lives = game.add.group();
game.add.text(game.world.width - 100, 10, 'Lives : ', { font: '34px Arial', fill: '#fff' });
// Text
stateText = game.add.text(game.world.centerX,game.world.centerY,' ', { font: '84px Arial', fill: '#fff' });
stateText.anchor.setTo(0.5, 0.5);
stateText.visible = false;
for (var i = 0; i < 3; i++)
{
var ship = lives.create(game.world.width - 100 + (30 * i), 60, 'ship');
ship.anchor.setTo(0.5, 0.5);
ship.angle = 90;
ship.alpha = 0.4;
}
// An explosion pool
explosions = game.add.group();
explosions.createMultiple(30, 'kaboom');
explosions.forEach(setupInvader, this);
// And some controls to play the game with
cursors = game.input.keyboard.createCursorKeys();
fireButton = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
}
function createAliens () {
for (var i=0; i<event.records.length;i++)
{
var alien = aliens.create(i * 48, 50, 'invader');
alien.anchor.setTo(0.5, 0.5);
alien.animations.add('fly', [ 0, 1, 2, 3 ], 20, true);
alien.play('fly');
alien.body.moves = false;
alien.scale.x = event.records[i].Scale.value;
alien.scale.y = event.records[i].Scale.value;
alien.health = event.records[i].Health.value;
}
aliens.x = 100;
aliens.y = 50;
// All this does is basically start the invaders moving. Notice we're moving the Group they belong to, rather than the invaders directly.
var tween = game.add.tween(aliens).to( { x: 200 }, 2000, Phaser.Easing.Linear.None, true, 0, 1000, true);
// When the tween loops it calls descend
tween.onLoop.add(descend, this);
}
function setupInvader (invader) {
invader.anchor.x = 0.5;
invader.anchor.y = 0.5;
invader.animations.add('kaboom');
}
function descend() {
aliens.y += 10;
}
function update() {
// Scroll the background
starfield.tilePosition.y += 2;
if (player.alive)
{
// Reset the player, then check for movement keys
player.body.velocity.setTo(0, 0);
if (cursors.left.isDown)
{
player.body.velocity.x = -200;
}
else if (cursors.right.isDown)
{
player.body.velocity.x = 200;
}
// Firing?
if (fireButton.isDown)
{
fireBullet();
}
if (game.time.now > firingTimer)
{
enemyFires();
}
// Run collision
game.physics.arcade.overlap(bullets, aliens, collisionHandler, null, this);
game.physics.arcade.overlap(enemyBullets, player, enemyHitsPlayer, null, this);
}
}
function render() {
// for (var i = 0; i < aliens.length; i++)
// {
// game.debug.body(aliens.children[i]);
// }
}
function collisionHandler (bullet, alien) {
// When a bullet hits an alien we kill them both
bullet.kill();
//alien.kill();
alien.damage(1);
// Increase the score
score += 20;
scoreText.text = scoreString + score;
// And create an explosion :)
var explosion = explosions.getFirstExists(false);
//explosion.reset(alien.body.x, alien.body.y);
explosion.reset(alien.body.center.x, alien.body.center.y);
explosion.play('kaboom', 30, false, true);
if (aliens.countLiving() == 0)
{
score += 1000;
scoreText.text = scoreString + score;
enemyBullets.callAll('kill',this);
stateText.text = " You Won, \n Click to restart";
stateText.visible = true;
//the "click to restart" handler
game.input.onTap.addOnce(restart,this);
}
}
function enemyHitsPlayer (player,bullet) {
bullet.kill();
live = lives.getFirstAlive();
if (live)
{
live.kill();
}
// And create an explosion :)
var explosion = explosions.getFirstExists(false);
explosion.reset(player.body.x, player.body.y);
explosion.play('kaboom', 30, false, true);
// When the player dies
if (lives.countLiving() < 1)
{
player.kill();
enemyBullets.callAll('kill');
stateText.text=" GAME OVER \n Click to restart";
stateText.visible = true;
//the "click to restart" handler
game.input.onTap.addOnce(restart,this);
}
}
function enemyFires () {
// Grab the first bullet we can from the pool
enemyBullet = enemyBullets.getFirstExists(false);
livingEnemies.length=0;
aliens.forEachAlive(function(alien){
// put every living enemy in an array
livingEnemies.push(alien);
});
if (enemyBullet && livingEnemies.length > 0)
{
var random=game.rnd.integerInRange(0,livingEnemies.length-1);
// randomly select one of them
var shooter=livingEnemies[random];
// And fire the bullet from this enemy
enemyBullet.reset(shooter.body.x, shooter.body.y);
game.physics.arcade.moveToObject(enemyBullet,player,120);
firingTimer = game.time.now + 2000;
}
}
function fireBullet () {
// To avoid them being allowed to fire too fast we set a time limit
if (game.time.now > bulletTime)
{
// Grab the first bullet we can from the pool
bullet = bullets.getFirstExists(false);
if (bullet)
{
// And fire it
bullet.reset(player.x, player.y + 8);
bullet.body.velocity.y = -400;
bulletTime = game.time.now + 200;
}
}
}
function resetBullet (bullet) {
// Called if the bullet goes out of the screen
bullet.kill();
}
function restart () {
// A new level starts
//resets the life count
lives.callAll('revive');
// And brings the aliens back from the dead :)
aliens.removeAll();
createAliens();
//revives the player
player.revive();
//hides the text
stateText.visible = false;
score = 0;
scoreText.text = scoreString + score;
}
});
})();
Top comments (4)
Code Vein does indeed offer a multiplayer component, which can add a whole new layer of enjoyment to the game. It's not just about tackling the challenging enemies and exploring the post-apocalyptic world solo; you can team up with friends or other players to take on the adventure together. So, yes, in a nutshell, Code Vein does have multiplayer features that can enhance your gaming experience and make it even more enjoyable. If you're interested in diving deeper into the specifics of how it all works, you can check out this link: is code vein multiplayer? The multiplayer aspect in Code Vein allows you to embark on co-op journeys, which can be a blast if you prefer to tackle the game's formidable bosses with some backup. It's a great way to strategize, share your experiences, and help each other out when the going gets tough.
Definetly like games and apps such as this one It's such an immerse world to delve into which can take up so much of your time when you get into it..
Yes, I really like the games and apps like this. I still remember when I have to create the very first app for my university project and how much issues I have to face. But time passes a friend help me and submitted the assignment of the app.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.