HTML5 game creation prototype – Bubbles 2
Talking about Bubbles 2 game, Game development, Javascript and Users contributions.
Learn cross platform HTML5 game development
Check my Gumroad page for commented source code, games and books.
Following the example published in HTML5 game creation prototype post, Esteban Gallardo from Free Creation Games shares with us a more compex prototype to create a game like Bubbles 2.
This is what you’ll get (not on IE):
And this is the commented javascript to manage the whole game:
// ************************************
// Class Ball
// The user will control the ball movements
// with the control keys.
// ************************************
function Ball()
{
// CONSTRUCTOR
this.x = 0;
this.y = 0;
this.vx = 0;
this.vy = 0;
this.radius = 10;
this.color = "#000000";
this.iterator =0;
// ------------------------------------
// Ball reset
this.ResetBall = function()
{
this.x = 0;
this.y = 0;
this.vx = 0;
this.vy = 0;
this.radius = 10;
this.color = "#000000";
this.iterator =0;
}
// ------------------------------------
// Ball's logic
this.Update = function()
{
if (m_controlMode==CONTROL_MODE_MOUSE)
{
if (m_mouseDown)
{
this.vx=(m_mousePositionX-this.x)/5;
this.vy=(m_mousePositionY-this.y)/5;
}
}
else
{
// PROCESS INPUT
if (m_keyPressedLeft) this.vx--;
if (m_keyPressedRight) this.vx++;
if (m_keyPressedUp) this.vy--;
if (m_keyPressedDown) this.vy++;
}
// BALL'S LOGIC
this.x+=this.vx;
this.y+=this.vy;
this.vx*=friction;
this.vy*=friction;
// CONTROL LIMITS
if (this.xSCREEN_WIDTH) this.x=SCREEN_WIDTH-this.radius;
if (this.y+this.radius>SCREEN_HEIGHT) this.y=SCREEN_HEIGHT-this.radius;
}
// ------------------------------------
// Ball's Render
this.Render = function()
{
// FILL AREA
/*
m_context.beginPath();
m_context.fillStyle=this.color;
m_context.arc(this.x,this.y,this.radius,0,Math.PI*2,true);
m_context.closePath();
m_context.fill();
*/
// DRAW BUBBLE
m_context.drawImage(m_bubbleImage, this.x-this.radius, this.y-this.radius, this.radius*2, this.radius*2);
}
}
// ************************************
// Class Item
// Represent the items that the user's ball can collide to
// ************************************
function Item(type)
{
// var TYPE_ITEM_BUBBLE = 1;
// var TYPE_ITEM_ENEMY = 2;
// CONSTRUCTOR
this.type = type;
this.x = 0;
this.y = 0;
this.vx = 0;
this.vy = 0;
this.radius = 0;
this.color = "#000000";
this.iterator = 0;
this.isAlive = false;
// ------------------------------------
// Item Initialitzation
this.Init = function(radiusIni, radiusEnd, speedIni, speedEnd)
{
this.isAlive = true;
this.radius = radiusIni+Math.floor(Math.random()*(radiusEnd-radiusIni));
this.x = Math.floor(Math.random()*SCREEN_WIDTH);
this.y = 0;
this.vx = 0;
this.vy = speedIni+Math.floor(Math.random()*(speedEnd-speedIni));
// alert("Item::Init: Initialitzation of a bubble::this.radius="+this.radius);
}
// ------------------------------------
// Reset the object to its initial values
this.ResetItem = function()
{
this.x = 0;
this.y = 0;
this.vx = 0;
this.vy = 0;
this.isAlive = false;
}
// ------------------------------------
// Check if the bubble collide with the bubble of the player
this.IsCollision = function()
{
if (this.isAlive)
{
if (Math.abs(this.x-m_ball.x)+Math.abs(this.y-m_ball.y)x)&&(this.y+this.widthText+10>y));
case 'center':
return ((this.x-5-(this.widthText/2)x)&&(this.y+this.widthText+10>y));
default:
return ((this.x-5x)&&(this.y+this.widthText+10>y));
break;
}
}
// ------------------------------------
// Render the text
this.Render = function()
{
// ++ RENDER ++
m_context.font = this.font;
m_context.textAlign = this.textAlign;
m_context.textBaseline = this.textBaseline;
this.sizeText = m_context.measureText(this.text);
this.widthText = this.sizeText.width;
// DRAW RECTANGLE IN THE BACKGROUND OF TEXT
if (enableBackground)
{
m_context.beginPath();
m_context.strokeStyle = '#000000';
m_context.fillStyle = this.color;
switch (align)
{
case 'left':
m_context.rect(this.x-5, this.y-5, this.widthText+10, this.heightText+10);
break;
case 'center':
m_context.rect(this.x-5-(this.widthText/2), this.y-5, this.widthText+10, this.heightText+10);
break;
case 'right':
break;
}
m_context.fill();
m_context.stroke();
}
// DRAW TEXT
if (enableBackground)
{
m_context.fillStyle = '#000000';
}
else
{
m_context.fillStyle = this.color;
}
m_context.fillText(this.text, this.x, this.y);
m_context.closePath();
}
}
// ++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++
// GLOBAL CODE
// ++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++++++++++++++
// ++ CONSTANTS ++
var SCREEN_WIDTH = 500;
var SCREEN_HEIGHT = 500;
var STATE_LOAD = 0;
var STATE_MENU = 1;
var STATE_RUN = 2;
var STATE_END = 3;
var CONTROL_MODE_KEYBOARD = 0;
var CONTROL_MODE_MOUSE = 1;
var TYPE_ITEM_BUBBLE = 1;
var TYPE_ITEM_ENEMY = 2;
var TOTAL_NUMBER_BUBBLES = 20;
var TOTAL_NUMBER_ENEMIES = 20;
// ++ MEMBERS ++
var m_context; // Document context
var m_state = STATE_LOAD; // Main game state
var m_iterator = 0;
var m_lastTime = 0; // The time of the last frame
var m_difTime = 0; // The time spent between two frames
var m_askToLose = false;
var m_score = 0;
var m_controlMode; // Select between two control modes (KEYBOARD,MOUSE)
var m_mouseDown; // Reports when the mouse is being pressed
var m_mousePositionX; // X coordinate of the pressed mouse
var m_mousePositionY; // Y coordinate of the pressed mouse
// BUTTONS
var m_playWidthMouse;
var m_playWidthKeyboard;
var m_pressHereToPlayAgain;
// IMAGES
var m_bgMenuImage;
var m_bgGameImage;
var m_bubbleImage;
var m_thornsImage;
// ACTORS
var m_ball;
var m_bubbles; // List of bubbles
var m_bubbleTimeGeneration=0; // Time acumulator
var m_bubbleTimeGeneration_Limit=2000; // Time needed between two bubble generations
var m_bubbleTimeGeneration_Factor=1.1; // Decrease factor in the generation bubble time
var m_enemies;
var m_enemyTimeGeneration=0; // Time acumulator
var m_enemyTimeGeneration_Limit=2000; // Time needed between two enemies generations
var m_enemyTimeGeneration_Factor=0.8; // Time decrease factor in the generation of an enemy
var m_level=1; // Game level
var m_timeLevelUp=0; // Time acumulator
var m_timeLevelUp_Limit = 15000; // Time to reach a level up
var m_timeLevelUp_Factor = 1.1; // Grow time factor for level up
var m_timeoutLevelUpTitle = 0; // Grow time factor for level up
// INPUT
var m_keyPressedLeft=false;
var m_keyPressedRight=false;
var m_keyPressedUp=false;
var m_keyPressedDown=false;
var friction=0.9;
// ------------------------------------
// OnKeyDown
document.onkeydown = function(event)
{
var key_pressed;
if(event == null)
{
key_pressed = window.event.keyCode;
}
else
{
key_pressed = event.keyCode;
}
switch(key_pressed)
{
case 37:
m_keyPressedLeft=true;
break;
case 38:
m_keyPressedUp=true;
break;
case 39:
m_keyPressedRight=true;
break;
case 40:
m_keyPressedDown=true;
break;
}
}
// ------------------------------------
// OnKeyUp
document.onkeyup = function(event)
{
var key_pressed;
if(event == null)
{
key_pressed = window.event.keyCode;
}
else
{
key_pressed = event.keyCode;
}
switch(key_pressed)
{
case 37:
m_keyPressedLeft=false;
break;
case 38:
m_keyPressedUp=false;
break;
case 39:
m_keyPressedRight=false;
break;
case 40:
m_keyPressedDown=false;
break;
}
}
// ------------------------------------
// Ask to create a new bubble
function AskNewBubble()
{
var i=0;
for (i=0;im_bubbleTimeGeneration_Limit)
{
m_bubbleTimeGeneration=0;
if (m_timeoutLevelUpTitle<=0) AskNewBubble();
}
// UPDATE BUBBLE
for (i=0;im_enemyTimeGeneration_Limit)
{
m_enemyTimeGeneration=0;
if (m_timeoutLevelUpTitle<=0) AskNewEnemy();
}
// UPDATE ENEMIES
for (i=0;im_timeLevelUp_Limit)
{
m_level++;
m_timeoutLevelUpTitle = 2000;
m_timeLevelUp = 0;
m_timeLevelUp_Limit*=m_timeLevelUp_Factor;
// CHANGE BUBBLE RATE
m_bubbleTimeGeneration_Limit*=m_bubbleTimeGeneration_Factor;
// CHANGE ENEMY RATE
m_enemyTimeGeneration_Limit*=m_enemyTimeGeneration_Factor;
}
if (m_timeoutLevelUpTitle>0)
{
m_timeoutLevelUpTitle -= m_difTime;
}
// EVALUATE MAIN GAME STATE
switch (m_state)
{
/////////////////////////
case STATE_LOAD:
switch (m_iterator)
{
case 1:
// INIT GRAPHICS
m_context=game_area.getContext('2d');
// LOAD IMAGES
m_bgGameImage = new Image();
m_bgGameImage.src = 'images/bg_game.jpg';
m_bubbleImage = new Image();
m_bubbleImage.src = 'images/bubble.png';
m_thornsImage = new Image();
m_thornsImage.src = 'images/thorns.png';
m_bgMenuImage = new Image();
m_bgMenuImage.onload = function() { m_iterator=100; };
m_bgMenuImage.src = 'images/bg_menu.jpg';
// INIT GAME ELEMENTS
m_ball = new Ball();
// BUBBLES INIT
m_bubbles=new Array(TOTAL_NUMBER_BUBBLES);
var i;
for (i=0;i0)
{
var titleLevelUp = new MyText('LEVEL '+m_level, SCREEN_WIDTH/2, (SCREEN_HEIGHT/4), 24, '#ffffff', '50px sans-serif', 'center', 'top', false);
titleLevelUp.Render();
}
// ++ END CONDITIONS ++
if (m_askToLose)
{
m_askToLose=true;
ChangeState(STATE_END);
}
break;
/////////////////////////
case STATE_END:
switch (m_iterator)
{
case 1:
// INIT TEXT
var titleGameOver = new MyText('GAME OVER',SCREEN_WIDTH/2,SCREEN_HEIGHT/6,24,'#ff0000', '30px sans-serif', 'center', 'top', true);
var titleFinalScore = new MyText('YOUR SCORE: '+m_score,SCREEN_WIDTH/2,SCREEN_HEIGHT/2,24,'#ffffff', '30px sans-serif', 'center', 'top', false);
m_pressHereToPlayAgain = new MyText('Press here to go to menu screen',SCREEN_WIDTH/2,5*SCREEN_HEIGHT/6,24,'#00ff00', '20px sans-serif', 'center', 'top', true);
// RENDER TEXT
titleGameOver.Render();
titleFinalScore.Render();
m_pressHereToPlayAgain.Render();
break;
}
// CHECK BUTTON SELECTION
if (m_mouseDown)
{
if (m_pressHereToPlayAgain.IsInside(m_mousePositionX,m_mousePositionY))
{
m_mouseDown=false;
ChangeState(STATE_MENU);
}
}
break;
}
}
// SET MAIN LOOP
setInterval(Update, 30);
Download the source code with all images.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.