Looking around for ideas on my site edoardoo.com (which is now restyled, have a look! ), I’ve decided to implement something that was pretty easy in my mind, just an animated falling lamp from the ceiling of the browser.
DEMO – GIT
Doing some researches I’ve seen that actually it was not easy at all. So I’ve thought about slicing the problem in little isolated problems:
- The wire
- The lamp body
- The light
- Details (eventually)
1) The Wire
Structure
The wire problem is how to implement it. In fact, in canvas 2d technology there isn’t a way to draw a “boned” object, like a rag doll, or a rope. Using 3d modelling, which can easily implements some sort of physic, was absolutely out of time budget and maybe an over sized solution.
What is, in the end, a rope? Actually it’s nothing more than a bunch of points glued together. Drawing a rope point-by-point could be extremely heavy to compute for a browser, I don’t want to imagine making them react to some sort of physic.
So I’ve thought about simplify the problem for the browser interpreting the rope like a bunch of segments, which react together following some physic rule.
Physic
I wanted to give my rope/wire a realistic movement based on gravity and inertia. After googling a bit, I’ve found one of the video gamers master piece technique: verlet integration.
This is not the place to discuss about how verlet integration works, because it could be really dispersive and, most of all, since this is a basic technique for game developers, you can find thousands of places around the web with beautiful tutorials (link to my favourite at the end of the section).
I’ll limit to say that verlet integration give us the physic rules we need, i.e. equipped with:
- inertia
- gravity
- constraints between segments (of the rope)
I refer you to read this awesome and really clear tutorial on GameDev about verlet integration.
Here is the functions I’ve used:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// //physics functions for Verlet integration // var physic = { ApplyUnitaryVerletIntegration: function (item, ellapsedTime, gravity, pixelsPerMeter) { item.x = 2 * item.x - item.old_x; // No acceleration here item.y = 2 * item.y - item.old_y + gravity * ellapsedTime * ellapsedTime * pixelsPerMeter; }, ApplyUnitaryDistanceRelaxation: function (item, from, targettedLength) { var dx = item.x - from.x; var dy = item.y - from.y; var dstFrom = Math.sqrt(dx * dx + dy * dy); if (dstFrom > targettedLength && dstFrom != 0 ) { item.x -= (dstFrom - targettedLength) * (dx / dstFrom) * 0.5; item.y -= (dstFrom - targettedLength) * (dy / dstFrom) * 0.5; } } } |
2) The lamp body
Structure
To draw the lamp I’ve used an image of an industrial lamp.
I’ve preloaded it, letting the animation begin only when loading is complete.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// //Preload the pictures to prevent javascript from stuck // //using two lamps, one with lights turned on, the other one turned off ropeDemo.context.img0 = new Image(); ropeDemo.context.img1 = new Image(); //IMPORTANT: Wait for the picture to be loaded! ropeDemo.context.img0.onload = function(){ // Start application ropeDemo.Start(); }; //yes, the src goes after ropeDemo.context.img0.src = 'lamp0.png'; ropeDemo.context.img1.src = 'lamp1.png'; |
Then drawn it with a simple
1 2 3 4 5 |
// //just draw the preloaded image // Context.drawImage(ropeDemo.context.img0,-150,-10); |
Physic
The lamp has a physic related to the movement of the rope, of course. But how to extract the lamp movement from the rope it’s attached by? I’ve just used a little trick.
I’ve calculated the angular coefficient of the line passing by the last point of the rope and 18 points before the last. This is the angle the lamp should have, or at least it looks something good.
1 2 3 4 5 6 |
// // item variable is, at this cycle, the last point of the rope // var item0 = ropeDemo.rope.items[index-18]; ropeDemo.rope.coeff = ((item.x + ropeDemo.context.center.x)- (item0.x + ropeDemo.context.center.x))/((item.y + ropeDemo.context.center.y)-(item0.y + ropeDemo.context.center.y)); |
3) The light
The light coming out of the lamp can be implemented in a lot of ways. From an image drawn on a context, to a triangle drawn in javascript and filled with a gradient, ending, why not, going out of the canvas, using some css3.
I’ve used the one where I was more comfortable with, maybe not the most elegant solution: draw a triangle.
The reasons of this decision are intrinsics inside the initial draft of the project. In fact, at the beginning I thought about a lamp already turned on, falling down from the ceiling and oscillating in the meantime. For this reason, the light had been able to be rotated to accomplish the lamp angle.
The easier way to implement this was to take the same angle of the lamp and rotate the light, using javascript.
Another good reason to implement the light in a dynamic structure, was the possibility to grab the lamp and move it (awesome, I know), option that has been abandoned due to a lack of time.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// //Light implementation // //draw the triangle ropeDemo.context.drawingContext.moveTo(item.x, item.y+170); ropeDemo.context.drawingContext.lineTo(3900, 1280); ropeDemo.context.drawingContext.lineTo(-3900,1280); ropeDemo.context.drawingContext.lineTo(item.x, item.y+170); //create a gradient var grd = ropeDemo.context.drawingContext.createRadialGradient(0, 0, 2, 640, 1030, 1280); grd.addColorStop(0, 'white'); grd.addColorStop(1, 'rgba(255, 255, 255, 0.6)'); //assign the gradient to fillstyle ropeDemo.context.drawingContext.fillStyle = grd; //fill the triangle ropeDemo.context.drawingContext.fill(); |
4) Details
After the structure with a working physic was done, it was just a matter of polishing.
Rope
To make the rope looks better I’ve removed the dots used to identify the segments and applied an horizontal gradient.
1 2 3 4 5 6 7 8 9 10 11 12 |
// //Create a gradient. It starts a little before the wire and ends a little bit after. // var grad= ropeDemo.context.drawingContext.createLinearGradient((ropeDemo.context.size.w * 0.5)-10, 0, (ropeDemo.context.size.w * 0.5)+20,0); grad.addColorStop(0, "#666666"); grad.addColorStop(1, "#111111"); //assign the gradient ropeDemo.context.drawingContext.strokeStyle = grad; ropeDemo.context.drawingContext.lineWidth = 7; ropeDemo.context.drawingContext.stroke(); |
Lamp
To give the lamp a more realistic effect I’ve created two version of the same object, one turned on and the other one turned off.
Going a little bit further, with the risk of being some kind of pathetic, I’ve added some metallic sound to the oscillating lamp.
Light
Using an alpha gradient instead of a full colour make the light look more familiar.
Again, with the risk of being pathetic, here is the sound of a blinking neon turning on, synced with the three flashes of the lamp.
Environment
As everyone knows, the devil is in the details. The first thing that come in my mind when I think about an industrial lamp, or a good light effect in general, is dust. What gives you the impression of light is the colour, of course, and the dust particles you can see through light beams.
So I’ve created two layers of dust, one with bigger and one with smaller particles, and I animated them at different speed (with some CSS3), creating a parallax effect. You can barely see it, like in real life.
Possible developments
All the code has been implemented in a very short period of time. It can be absolutely improved (using sprites for pictures, cleaning the code, add resizing, etc…).
One of the possible feature which has been partially implemented is the possibility of grabbing the lamp and release it, making it oscillating (I have no idea of what to do with the sound here). The biggest problem I’ve encountered was the lamp going over the screen top, or starting to react in a really weird way when the release point was too far from the origin.
A special thanks goes to the author of this post which pointed me in the right way.
offline is not working. the light do not show up. why?
If you can produce it for me that would be great. Is that possible?
Thanks
I would suggest you to have a nice day playing CSS3 and very little bit of JS, because it’s funny, intuitive and, with all the tutorials around, almost painless. Plus, you’ll learn how to manage little animations for future develops.
Anyway, if you don’t have time to do this, or if you just hate coding, I can make it for you. In the end, this is my job :D. Send me a detailed request (with some drafts) at edo [at ] lenotta.com . I’ll reply as soon as possible with a quote.
Have a nice day.
Hello Edoardo,
thanks for the useful info actually when you talking about batman my goal is this:
I would like to create and light beam behind the skyline that would do similar as batman, but with the effect as the lamp the sound and flicker and on the sky would show the logo.
Like this:
http://www.charlesapple.com/uploads/2012/07/120720BatmanSkyboxOmahaNeb-400×156.jpg
The light beam would do the same as your lamp light flicker sound etc….I would like to have it on the background of my site and instead of the batman logo would be my logo…do you think you can do that?
Of course I can, but I’m really busy at work this month. Would you like me to produce it for you or do you need help on understanding how to achieve the final effect?
Addition:
It can be the same beam that you have for the lamp, just need to know how to make the orientation right.
Thanks
Hi Radek,
sorry for late response. Of course you can. Although I would adopt a slightly different approach.
In order, i would build it by:
1) creating a fullscreen div (let’s call it outDarkness ) and an inside div (which we’ll call beamLight )
The outDarkness will be the dark, or background color, and the beamLight will be our, yeah, light beam.
2) Set outDarkness background color css property as #333 (dark gray). Then go to http://www.colorzilla.com/gradient-editor/ and create a diagonal gradient of yellow (or pink, red, green… ) to alpha.
3) rotate, translate and skew the beamLight div with css3 properties transformation as you wish.
4) animate it using CSS3 animations. I’ve used simple CSS3 animations in http://hack.lenotta.com/html5-and-css3-loading-rotating-arrows-without-gif/ and http://hack.lenotta.com/css3-batman-helps-you/ (and surely somewhere else), but you can find examples all around the web.
Hope you’ll manage to solve your problem. Let us now how it’s gone.
Have a nice day.
Approaching with CSS3 will make your effect and animation extremely more smooth and fluid.
Hello,
its very nice article and demo.
I am not a strong programmer in js but I can read it in some kind of way. I was wondering regarding only the light.
I would like to achieve (no lamp at all) that the beam would start from the bottom left corner under 45 deg up.
Is there an easy way to achieve this? like this but from the bottom left up
http://www.skylighters.org/dutch/images/lite10.jpg
Thanks
Hello again Edoardo
Thank you so much for going to the trouble of preparing the rope sim for me
It works great. Don’t worry about the slider panel, its really just the verlet integration that I would like to study
I’m not such a strong programmer, so its going to take some time to get my head round things !
I’ll pay your site a visit again in the near future so see what other cool stuff you have been up to …
Thanks again
Matt
p.s. I’m not a prof, or even a dr, but thanks for being so polite !
Glad you like it, I forgot to say I’ve enabled the drag feature on the rope. Have fun!
Hi Edoardo
Excellent blog, I have really enjoyed browsing some of your creations.
I am a physics teacher, and I would like to know more about how you created the swinging rope.
I downloaded your code from Git Hub, but I am struggling to disect it.
Might you be able to provide me with the code for the “bare bones” swinging rope? i.e. a working version, without the lamp, just the segmented rope.
I am not very good at programming, but I would like to use the rope in my lessons.
Thank you, and keep up the good work !
Matt Klein, London, UK
Hi Matt,
I would be glad help to help you, although I need some time to prepare the material.
From what I remember, I kept the physic separated (in another js file), so it should be easy to find it (it was helpful for me too).
Anyway, I’ll prepare a commented file just for you as soon as I can.
Have a nice day.
Thanks Edoardo, that would be great. Yes, I found the separate physics file, but I have been struggling to remove the rest of the code (e.g. the images, sound etc). I would like just a simple swinging rope…
Thanks again
Hi Matt,
some time has passed, but as I promised here is the link to you request:
https://github.com/edoardoo/DynamicRope
I’ve also implemented a little panel with some slider to change values, but I didn’t have the time to make it work completely. Everything is set, the only thing to do is to get the right value from the slider.
Have fun!