HTML5 prototype of a circular endless runner featuring double jump built with Phaser – handling collisions without physics
Talking about Circular endless runner game, Game development, HTML5, Javascript and Phaser.
Do you like my tutorials?
Then consider supporting me on Ko-fi.
var game;
var gameOptions = {
bigCircleRadius: 250,
playerRadius: 25,
playerSpeed: 1,
worldGravity: 0.8,
jumpForce: [12, 8],
spikeSize: [25, 50],
closeToSpike: 10,
farFromSpike: 25
}
window.onload = function() {
var gameConfig = {
thpe: Phaser.CANVAS,
width: 800,
height: 800,
scene: [playGame]
}
game = new Phaser.Game(gameConfig);
window.focus()
resize();
window.addEventListener("resize", resize, false);
}
class playGame extends Phaser.Scene{
constructor(){
super("PlayGame");
}
preload(){
this.load.image("bigcircle", "bigcircle.png");
this.load.image("player", "player.png");
this.load.image("spike", "spike.png");
}
create(){
this.graphics = this.add.graphics();
this.bigCircle = this.add.sprite(game.config.width / 2, game.config.height / 2, "bigcircle");
this.bigCircle.displayWidth = gameOptions.bigCircleRadius * 2;
this.bigCircle.displayHeight = gameOptions.bigCircleRadius * 2;
this.player = this.add.sprite(game.config.width / 2, game.config.height / 2 - gameOptions.bigCircleRadius - gameOptions.playerRadius, "player");
this.player.displayWidth = gameOptions.playerRadius * 2;
this.player.displayHeight = gameOptions.playerRadius * 2;
this.player.currentAngle = -90;
this.player.jumpOffset = 0;
this.player.jumps = 0;
this.player.jumpForce = 0;
this.spikeGroup = this.add.group();
this.input.on("pointerdown", function(e){
if(this.player.jumps < 2){
this.player.jumps ++;
this.player.jumpForce = gameOptions.jumpForce[this.player.jumps - 1];
}
}, this);
for(var i = 0; i < 6; i ++){
var spike = this.add.sprite(0, 0, "spike");
spike.setOrigin(0, 0.5);
this.spikeGroup.add(spike);
this.placeSpike(spike, Math.floor(i / 2));
}
}
placeSpike(spike, quadrant){
var randomAngle = Phaser.Math.Between(quadrant * 90, (quadrant + 1) * 90);
randomAngle = Phaser.Math.Angle.WrapDegrees(randomAngle);
var randomAngleRadians = Phaser.Math.DegToRad(randomAngle);
var spikeX = this.bigCircle.x + (gameOptions.bigCircleRadius - 4) * Math.cos(randomAngleRadians);
var spikeY = this.bigCircle.y + (gameOptions.bigCircleRadius - 4) * Math.sin(randomAngleRadians);
spike.x = spikeX;
spike.y = spikeY;
spike.quadrant = quadrant;
spike.angle = randomAngle;
spike.top = new Phaser.Math.Vector2(spikeX + gameOptions.spikeSize[1] * Math.cos(randomAngleRadians), spikeY + gameOptions.spikeSize[1] * Math.sin(randomAngleRadians));
spike.base1 = new Phaser.Math.Vector2(spikeX + gameOptions.spikeSize[0] / 2 * Math.cos(randomAngleRadians + Math.PI / 2), spikeY + gameOptions.spikeSize[0] / 2 * Math.sin(randomAngleRadians + Math.PI / 2));
spike.base2 = new Phaser.Math.Vector2(spikeX + gameOptions.spikeSize[0] / 2 * Math.cos(randomAngleRadians - Math.PI / 2), spikeY + gameOptions.spikeSize[0] / 2 * Math.sin(randomAngleRadians - Math.PI / 2));
spike.approaching = false;
}
update(){
if(this.player.jumps > 0){
this.player.jumpOffset += this.player.jumpForce;
this.player.jumpForce -= gameOptions.worldGravity;
if(this.player.jumpOffset < 0){
this.player.jumpOffset = 0;
this.player.jumps = 0;
this.player.jumpForce = 0;
}
}
this.player.currentAngle = Phaser.Math.Angle.WrapDegrees(this.player.currentAngle + gameOptions.playerSpeed);
var radians = Phaser.Math.DegToRad(this.player.currentAngle);
var distanceFromCenter = (gameOptions.bigCircleRadius * 2 + gameOptions.playerRadius * 2) / 2 + this.player.jumpOffset;
this.player.x = this.bigCircle.x + distanceFromCenter * Math.cos(radians);
this.player.y = this.bigCircle.y + distanceFromCenter * Math.sin(radians);
var revolutions = (gameOptions.bigCircleRadius * 2) / (gameOptions.playerRadius * 2) + 1;
this.player.angle = this.player.currentAngle * revolutions;
this.graphics.clear();
this.spikeGroup.children.iterate(function(spike){
var angleDiff = this.getAngleDifference(spike.angle, this.player.currentAngle);
if(!spike.approaching && angleDiff < gameOptions.closeToSpike){
spike.approaching = true;
}
if(spike.approaching){
this.graphics.lineStyle(4, 0xff0000);
this.graphics.beginPath();
this.graphics.moveTo(spike.top.x, spike.top.y);
this.graphics.lineTo(spike.base1.x, spike.base1.y);
this.graphics.closePath();
this.graphics.strokePath();
this.graphics.beginPath();
this.graphics.moveTo(spike.top.x, spike.top.y);
this.graphics.lineTo(spike.base2.x, spike.base2.y);
this.graphics.closePath();
this.graphics.strokePath();
if(this.distToSegmentSquared(new Phaser.Math.Vector2(this.player.x, this.player.y), gameOptions.playerRadius, spike.top, spike.base1) || this.distToSegmentSquared(new Phaser.Math.Vector2(this.player.x, this.player.y), gameOptions.playerRadius, spike.top, spike.base2)){
this.scene.start("PlayGame");
}
if(angleDiff > gameOptions.farFromSpike){
this.placeSpike(spike, (spike.quadrant + 3) % 4);
}
}
}, this)
}
getAngleDifference(a1, a2){
var angleDifference = a1 - a2
angleDifference += (angleDifference > 180) ? -360 : (angleDifference < -180) ? 360 : 0
return Math.abs(angleDifference);
}
getDistance(p1, p2){
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
distToSegmentSquared(circleCenter, circleRadius, segmentStart, segmentEnd){
var l2 = this.getDistance(segmentStart, segmentEnd);
var t = ((circleCenter.x - segmentStart.x) * (segmentEnd.x - segmentStart.x) + (circleCenter.y - segmentStart.y) * (segmentEnd.y - segmentStart.y)) / l2;
t = Math.max(0, Math.min(1, t));
var tX = segmentStart.x + t * (segmentEnd.x - segmentStart.x);
var tY = segmentStart.y + t * (segmentEnd.y - segmentStart.y);
var tPoint = {
x: tX,
y: tY
}
return this.getDistance(circleCenter, tPoint) < circleRadius * circleRadius;
}
}
// pure javascript to scale the game
function resize() {
var canvas = document.querySelector("canvas");
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var windowRatio = windowWidth / windowHeight;
var gameRatio = game.config.width / game.config.height;
if(windowRatio < gameRatio){
canvas.style.width = windowWidth + "px";
canvas.style.height = (windowWidth / gameRatio) + "px";
}
else{
canvas.style.width = (windowHeight * gameRatio) + "px";
canvas.style.height = windowHeight + "px";
}
}
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.