
HTML5 Game Development – Lesson 2. Today we continue a series of articles on game development in HTML5. Today we will continue basics (and maybe even advanced basics). I going to show you how to fill objects with gradient color, draw text, use custom fonts to draw text, basic animation, and most important: ui element – Button.
Our previous article you can read here: Developing Your First HTML5 Game – Lesson 1. I going to work with our previous script – we will just enhance it. I going to draw text using custom font, animate object (square) filled with gradient color, and will draw ‘Play / Pause’ button to pausing animation.
Here are our demo and downloadable package:
Live Demo
Ok, download the example files and lets start coding !
Step 1. HTML
Here are all html of my demo
index.html
<!DOCTYPE html> <html lang="en" > <head> <meta charset="utf-8" /> <title>HTML5 Game Development - Lesson 2 | Script Tutorials</title> <link href="css/main.css" rel="stylesheet" type="text/css" /> <!--[if lt IE 9]> <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <script type="text/javascript" src="js/jquery-1.5.2.min.js"></script> <script type="text/javascript" src="js/script.js"></script> </head> <body> <div class="container"> <canvas id="scene" width="800" height="600"></canvas> </div> <footer> <h2>HTML5 Game Development - Lesson 2</h2> <a href="https://script-tutorials.com/html5-game-development-lesson-2" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a> </footer> </body> </html>
Step 2. CSS
Here are used CSS styles.
css/main.css
/* general styles */ *{ margin:0; padding:0; } @font-face { font-family: "DS-Digital"; src: url("../fonts/Ds-digib.ttf"); } body { background-color:#bababa; background-image: -webkit-radial-gradient(600px 300px, circle, #ffffff, #bababa 60%); background-image: -moz-radial-gradient(600px 300px, circle, #ffffff, #bababa 60%); background-image: -o-radial-gradient(600px 300px, circle, #ffffff, #bababa 60%); background-image: radial-gradient(600px 300px, circle, #ffffff, #bababa 60%); color:#fff; font:14px/1.3 Arial,sans-serif; min-height:1000px; } .container { width:100%; } .container > * { display:block; margin:50px auto; } footer { background-color:#212121; bottom:0; box-shadow: 0 -1px 2px #111111; display:block; height:70px; left:0; position:fixed; width:100%; z-index:100; } footer h2{ font-size:22px; font-weight:normal; left:50%; margin-left:-400px; padding:22px 0; position:absolute; width:540px; } footer a.stuts,a.stuts:visited{ border:none; text-decoration:none; color:#fcfcfc; font-size:14px; left:50%; line-height:31px; margin:23px 0 0 110px; position:absolute; top:0; } footer .stuts span { font-size:22px; font-weight:bold; margin-left:5px; } h3 { text-align:center; } #scene { background-image:url(../images/01.jpg); position:relative; }
Pay attention to ‘@font-face’. We will using this way to link custom font file (ttf) to our lesson (to draw at canvas).
Step 3. JS
js/jquery-1.5.2.min.js
We will using jQuery for our demo. This allows easy bind different events (for mouse etc). Next file most important (here are all our html5 functional):
js/script.js
var canvas, ctx; var circles = []; var selectedCircle; var hoveredCircle; var button; var moving = false; var speed = 2.0; // ------------------------------------------------------------- // objects : function Circle(x, y, radius){ this.x = x; this.y = y; this.radius = radius; } function Button(x, y, w, h, state, image) { this.x = x; this.y = y; this.w = w; this.h = h; this.state = state; this.imageShift = 0; this.image = image; } // ------------------------------------------------------------- // draw functions : function clear() { // clear canvas function ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); } function drawCircle(ctx, x, y, radius) { // draw circle function ctx.fillStyle = 'rgba(255, 35, 55, 1.0)'; ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI*2, true); ctx.closePath(); ctx.fill(); ctx.lineWidth = 1; ctx.strokeStyle = 'rgba(0, 0, 0, 1.0)'; ctx.stroke(); // draw border } function drawScene() { // main drawScene function clear(); // clear canvas // draw the title text ctx.font = '42px DS-Digital'; ctx.textAlign = 'center'; ctx.fillStyle = '#ffffff'; ctx.fillText('Welcome to lesson #2', ctx.canvas.width/2, 50); var bg_gradient = ctx.createLinearGradient(0, 200, 0, 400); bg_gradient.addColorStop(0.0, 'rgba(255, 0, 0, 0.8)'); bg_gradient.addColorStop(0.5, 'rgba(0, 255, 0, 0.8)'); bg_gradient.addColorStop(1.0, 'rgba(0, 0, 255, 0.8)'); ctx.beginPath(); // custom shape begin ctx.fillStyle = bg_gradient; ctx.moveTo(circles[0].x, circles[0].y); for (var i=0; i<circles.length; i++) { ctx.lineTo(circles[i].x, circles[i].y); } ctx.closePath(); // custom shape end ctx.fill(); // fill custom shape ctx.lineWidth = 2; ctx.strokeStyle = 'rgba(0, 0, 255, 0.5)'; ctx.stroke(); // draw border // reverting direction if (circles[0].x <= 300 || circles[0].x >= 385) { speed = -speed; } // central object behavior if (moving) { circles[0].x -= speed; circles[0].y -= speed; circles[1].x += speed; circles[1].y -= speed; circles[2].x += speed; circles[2].y += speed; circles[3].x -= speed; circles[3].y += speed; } drawCircle(ctx, circles[0].x, circles[0].y, (hoveredCircle == 0) ? 25 : 15); drawCircle(ctx, circles[1].x, circles[1].y, (hoveredCircle == 1) ? 25 : 15); drawCircle(ctx, circles[2].x, circles[2].y, (hoveredCircle == 2) ? 25 : 15); drawCircle(ctx, circles[3].x, circles[3].y, (hoveredCircle == 3) ? 25 : 15); // draw button ctx.drawImage(button.image, 0, button.imageShift, button.w, button.h, button.x, button.y, button.w, button.h); // draw text ctx.font = '30px DS-Digital'; ctx.fillStyle = '#ffffff'; ctx.fillText('Play/Pause', 135, 480); ctx.fillText(button.state, 135, 515); } // ------------------------------------------------------------- // initialization $(function(){ canvas = document.getElementById('scene'); ctx = canvas.getContext('2d'); var circleRadius = 15; var width = canvas.width; var height = canvas.height; // lets add 4 circles manually circles.push(new Circle(width / 2 - 20, height / 2 - 20, circleRadius)); circles.push(new Circle(width / 2 + 20, height / 2 - 20, circleRadius)); circles.push(new Circle(width / 2 + 20, height / 2 + 20, circleRadius)); circles.push(new Circle(width / 2 - 20, height / 2 + 20, circleRadius)); // load the guide sprite image buttonImage = new Image(); buttonImage.src = 'images/button.png'; buttonImage.onload = function() { } button = new Button(50, 450, 180, 120, 'normal', buttonImage); // binding mousedown event (for dragging) $('#scene').mousedown(function(e) { var mouseX = e.layerX || 0; var mouseY = e.layerY || 0; for (var i=0; i<circles.length; i++) { // checking through all circles - are mouse down inside circle or not var circleX = circles[i].x; var circleY = circles[i].y; var radius = circles[i].radius; if (Math.pow(mouseX-circleX,2) + Math.pow(mouseY-circleY,2) < Math.pow(radius,2)) { selectedCircle = i; break; } } // button behavior if (mouseX > button.x && mouseX < button.x+button.w && mouseY > button.y && mouseY < button.y+button.h) { button.state = 'pressed'; button.imageShift = 262; } }); $('#scene').mousemove(function(e) { // binding mousemove event for dragging selected circle var mouseX = e.layerX || 0; var mouseY = e.layerY || 0; if (selectedCircle != undefined) { // var canvasPosition = $(this).offset(); var radius = circles[selectedCircle].radius; circles[selectedCircle] = new Circle(mouseX, mouseY,radius); // changing position of selected circle } hoveredCircle = undefined; for (var i=0; i<circles.length; i++) { // checking through all circles - are mouse down inside circle or not var circleX = circles[i].x; var circleY = circles[i].y; var radius = circles[i].radius; if (Math.pow(mouseX-circleX,2) + Math.pow(mouseY-circleY,2) < Math.pow(radius,2)) { hoveredCircle = i; circles[hoveredCircle] = new Circle(circleX, circleY, 25); break; } } // button behavior if (button.state != 'pressed') { button.state = 'normal'; button.imageShift = 0; if (mouseX > button.x && mouseX < button.x+button.w && mouseY > button.y && mouseY < button.y+button.h) { button.state = 'hover'; button.imageShift = 131; } } }); $('#scene').mouseup(function(e) { // on mouseup - cleaning selectedCircle selectedCircle = undefined; // button behavior if (button.state == 'pressed') { moving = !moving; } button.state = 'normal'; button.imageShift = 0; }); setInterval(drawScene, 30); // loop drawScene });
Here are several explanations about new features. 1. We can draw text (with custom font) using next code:
ctx.font = '42px DS-Digital'; ctx.textAlign = 'center'; ctx.fillStyle = '#ffffff'; ctx.fillText('Welcome to lesson #2', ctx.canvas.width/2, 50);
2. Applying gradient color to objects:
var bg_gradient = ctx.createLinearGradient(0, 200, 0, 400); bg_gradient.addColorStop(0.0, 'rgba(255, 0, 0, 0.8)'); bg_gradient.addColorStop(0.5, 'rgba(0, 255, 0, 0.8)'); bg_gradient.addColorStop(1.0, 'rgba(0, 0, 255, 0.8)'); ctx.fillStyle = bg_gradient;
3. Button itself – I used one sprite image with all 3 button states. Also I added event handlers to hover/down events. Here are way of loading and drawing image at canvas:
buttonImage = new Image(); buttonImage.src = 'images/button.png'; ....... ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, width, height);
Step 4. Custom files
fonts/Ds-digib.ttf and images/button.png
Both files will available in our package
Live Demo
Conclusion
Cool, isn’t it? I will be glad to see your thanks and comments. Good luck!
Hi,
first of all thanks for your nice tutorial. I want to learn HTML 5 and JS especially because of game development and I find your tutorial quite helpful. I went through first part and it is very helpful for beginners as I am. I really appreciate the adding new functionality to existing example gradually. Hope you will continue…
Hi, Yes, don`t worry, I will continue this thread of game-dev related articles, finally we will come to some nice result (ready simple game)
Hi
Thanks for great contribution. I have passed first lesson. Now on second one, seems very cool explanation sequence. I have plan to finish your all the lesson.
Actually, my final goal to implement like http://www.crystal.ch/abb/power_systems_landscape/ using html5.
Can anyone give me idea just for following behavior of above link ?
1. whole canvas content including background can move left to right smoothly using mousemove and mousedown operation
2. Zoom in zoom out
Hi Shahdat,
Thanks for your comment, and, this is not so difficult to repeat the same behavior as at that flash demo. Anything is pretty easy. It will require:
a) good detailed image plan
b) time ( to product codes )
Hey~
Thinks for your comment,i found that promble about function
“drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)” in chrome
if sy+sh > image’s max height,the canvas cannot draw the image, but there is no promble in ie 9
i saw this problem when i mousedown the button.
hi.
i don’t know what role in program about the field imageShift, can you explain?
Hi Bells,
It is used to display different zones of ‘images/button.png’ image
Awesome.. keep posting! Thank you :)
I think the code
” if (circles[0].x = 385) {
speed = -speed;
}”
should be changed
var speed = 2.0;
var movingwidth=85;
var movingwidth=85;
if(movingwidth= 85){
speed = -speed;
}
Hi jhonwen,
I’m not sure, your code is erroneous.