How to apply grayscale filter to image using EaselJS (CreateJS)
Searching the Google for grayscale easeljs leads to some
obscure StackOverflow Q&A from 2011. which has a working example.
However, it uses a generic filter matrix so you would need to know how
grayscale effect actually works on pixel level to understand what it
does.
It's much easier to use Easel's built-in functions. However, those
are not easy to discover using a search engine. You have to dig into
docs. Here's an easy way to do it, adapted from Easel docs.
Assuming you have a Bitmap, Container, Shape in variable myDisplayObject:
var matrix = new createjs.ColorMatrix().adjustSaturation(-100);
myDisplayObject.filters = [new createjs.ColorMatrixFilter(matrix)];
myDisplayObject.cache();
Make sure you call cache() at the end, because filters are only applied
during caching. If you wish to use different filters for different objects
in a container, you need to cache() each one separately before adding
to container.
Now, you might run this example, and get the error message createjs.ColorMatrix() is not a constructor
because createjs.ColorMatrix is undefined. The reason for this is that
current version of minified files does not include filters, so you
need to include ColorMatrixFilter.js script in your page
separately. Lanny says
it will be included in one of future versions. I'm not sure that's a good
idea though. I doubt many users use filters. I almost built the entire
game without it, and only want to include it for Medusa's petrifying
effects.
Feedback & Share
Milan Babuškov, 2013-06-18
Callback when all images in HTML page are loaded, with custom timeout
I'm developing a HTML5 game and although there are many ways to
track image loading, they mostly use XHR which does not work reliably
in different browsers. I don't care about progress bars, but I do
compose images after loading (using EaselJS cache) and need to make
sure images are loaded before caching.
The usage is really simple. In case some of the images fail to load,
or takes too long, you could have a problem that program would not
go on, and user won't see anything. To avoid this, I added a custom
timeout, after which the callback would be called regardless. The
timeout resets after each successfull download, so don't set it
too high. The example below uses 12 seconds:
// 1. create image loader
var imageLoader = new ImageLoader(12);
// 2. feed it some URLs
imageLoader.add('shadow', 'http://mycnd.com/shadow.jpg');
imageLoader.add('ball', 'http://mycnd.com/ball.png');
imageLoader.add('player', 'http://mycnd.com/player.png');
// 3. wait for load to complete and then do something with the images
imageLoader.loadAll(function() {
// do something, like for example:
var ballSprite = new createjs.Bitmap(
imageLoader.get('ball'));
});
The code uses alert() in two places. Please replace that with
whatever error handling you use.
Also, there could be a better/faster way to detect image files that are
not available (HTTP code 404 and similar), so that we don't have to
wait for timeout.
View and download the source code at https://github.com/mbabuskov/ImageLoader.
Feedback & Share
Milan Babuškov, 2013-06-10
Creating multiple sprites from the same image using EaselJS
In the HTML5 game I'm making, I needed to have many identical sprites.
At first, I used the generic new Bitmap('path.png') code, but it
uses a lot of memory that way. I searched the web and finally asked at
CreateJS forums. The answer is simple and easy:
var image = new Image(); // create HTML5 image object
image.src = 'url.png'; // load image from file
// now, just repeat the following for each sprite
var sprite = new Bitmap(image);
BTW, I did search for image class in EaselJS docs, but apparently
it is not listed as it is a regular HTML5 type of object. I guess you
should still learn HTML5 basics even if you use a wrapper library.
Feedback & Share
Milan Babuškov, 2013-05-29
How to load data from QHI.DAT file
If you have an old Quicken Home Inventory or Quicken Home Inventory
Manager installation and want to
save your inventory database, you probably have problems using this
data on a new computer system. This is because of various incompatibilities
between multiple versions of Intuit inventory programs.
However, there's a simple way out. Download a program called Attic
Manager. It's a home inventory program, just like QHIM, with one specific
feature: it is able to import databases of all Quicken Home
Inventory programs. At the time I write this, it supports the oldest IDB
files, then the newer .QHI files and also the latest MDF files which
come with most recent versions of Quicken.
Now, how does this help you, when you have a DAT file? Well, QHI.DAT
is not really a database with your items. If you have QHI.DAT file,
this means you have the oldest version of QHI, and there should be
a file called QHI.IDB around as well. Attic Manager is able to load all
items, locations, categories and other data from QHI.IDB file, so use
that one.
As far as I know, Attic Manager is the only product on the market
that is able to do this. Once you load the database into Attic Manager,
you can export it into CSV format and then load into any Inventory program
that supports loading from CSV or Excel (most of them do). Or, you can
simply use Attic Manager itself. It is simple, clean, and fast. It
works on newer versions of Windows, like Windows 7 and Windows 8 and also
on 64bit systems as well. And
knowing your data can be exported at any time sets you free from vendor
lock-in.
Feedback & Share
Milan Babuškov, 2013-05-15
Easel.js docs need improvement
A few days ago, Sebastian DeRossi asked
me on Twitter how to improve Easel.js
docs. As this is too large for Twitter's 140 characters, here's
a short blog post of some issues I found:
1. I was looking for a way to Flip an image and docs don't mention
that you can use negative values to scaleX and scaleY. I was really
planning to work around this by creating all the required mirror
images using ImageMagic and load 2 sets of sprites, when I accidentally
found the example using negative values on some blog while searching
for something completely different.
2. Say you are a complete beginner like me, and you wish to add a
mouse click event handler to Bitmap. You would go into docs,
click Bitmap, go
to list of events, where it says Click and there
are links to DisplayObject and MouseEvent there, but none of those
lead to example how to actually use it. Failing this, I first
found onClick only to find out that it is
deprecated and I should use addEventListener(), without any example
how to use it. BTW, I did manage to get onClick to work, but I did
not want to use a deprecated function. In the end, I asked on StackOverflow
and got a real example how to use addEventListener for mouse events.
3. The thing I'm still confused about, is what is the standard application
structure. I.e. how to do the main game loop? In docs, the
Getting Started
section ends with this:
//Update stage will render next frame
createjs.Ticker.addEventListener("tick", handleTick);
function handleTick() {
//Circle will move 10 units to the right.
circle.x += 10;
//Will cause the circle to wrap back
if (circle.x > stage.canvas.width) { circle.x = 0; }
stage.update();
}
Am I supposed to update all my logic in handleTick()? I would create
my own functions of course, and call it from there. Should the structure
of my program look like this:
createjs.Ticker.addEventListener("tick", handleTick);
function handleTick() {
updateWorldLogic();
stage.update();
}
Somewhere else, I found an example like this:
var canvas = document.getElementById("canvas_id");
startGame();
function startGame() {
stage = new createjs.Stage(canvas);
// NOTE the following comment, I have NO idea what it means???
// We want to do some work before we update the canvas,
// otherwise we could use Ticker.addListener(stage);
createjs.Ticker.addListener(window);
createjs.Ticker.useRAF = true;
createjs.Ticker.setFPS(60);
}
function tick()
{
// update the stage:
stage.update();
}
This code works, but I don't understand the difference between:
- createjs.Ticker.addListener(window);
- createjs.Ticker.addListener(stage);
- createjs.Ticker.addEventListener("tick", handleTick);
...and I'm having a hard time getting this clear from the docs.
Feedback & Share
Milan Babuškov, 2013-05-13
How to flip an image horizontaly or vertically using easel.js
Looking at Easel.js docs, you might think that Flip() function is
missing. However, flipping is done using scale with negative
values. To flip image horizontally, use:
image.scaleX = -1;
To flip vertically, use:
image.scaleY = -1;
Before flipping, make sure you set the regX and/or regY to the center
of image. Full example with image sized 120x50:
var myimg = new createjs.Bitmap("sword.png");
myimg.regX = 60;
myimg.regY = 25;
myimg.scaleX = -1; // flip horizontally
myimg.scaleY = -1; // flip vertically
Feedback & Share
Milan Babuškov, 2013-05-08
Creating a mouse hover effect for button/image with HTML5 Canvas and easel.js
After ditching many other HTML5 Canvas libs, I was left with Easel.js.
Documentation is sparse, without many examples. I had to google a lot
to find this information, so I'm getting it up here hoping it might help
someone else as well.
If you need a simple graphic (or text) button with hover support,
then Easel's ButtonHelper class is what you need. You can create a simple
image containing 3 buttons states (normal, hover, pressed) and set up
ButtonHelper to do all the work.
Here's how I did it. First create an image with all 3 states. I used
this PNG:
As you can see my image is 300x45 with each state being 100x45 pixels.
Now the code:
// setup
stage.enableMouseOver();
var data = {
images: ["3buttons.png"],
frames: {width:100, height:45},
animations: {normal:[0], hover:[1], clicked:[2]}
};
var spriteSheet = new createjs.SpriteSheet(data);
var button = new createjs.BitmapAnimation(spriteSheet);
var helper = new createjs.ButtonHelper(button, "normal", "hover", "clicked");
// set the button coordinates and display it on the screen
button.x = 100;
button.y = 100;
button.gotoAndStop("normal");
Yes, that's all. If you're looking for example with Text, take a
look at this jsFiddle.
Note that each of the button states can be animated, just add more
frames to the image file and configure the data.animations properly.
Feedback & Share
Milan Babuškov, 2013-05-08
Selecting a HTML5 Canvas library for a turn-based strategy game
In the past couple of days I had determined to select a HTML5 Canvas library
to use for my next game project. Some of the features I require:
- Scaling and rotating support with Tweening
- Availability or ready-made resource (images, audio) loader or able to easily make your own
- Ability to click on a random image or text element (sprite) and handle the event easily, like jQuery 'click' handler
- Ability to easily make hover effect over images/text
- Some other stuff like Flip is desired by not absolutely required
After investigating a lot of frameworks, I narrowed the list down to:
Crafty, MelonJS, Quintus, LimeJS, CanvasEngine, Cocos2d-hmtl5, CreateJS/EaselJS.
Crafty does not have rotating support, MelonJS and Cocos2d require that you
manually, traverse all the child nodes, find which ones are visible and
hittest the mouse coordinates to get the hover effect. I could not find
this information of Lime.js, but inability to preload audio turned me off.
Quintus apparently
does not support hover at all. So, I was left with CanvasEngine and EaselJS.
RPG.js is moving to CanvasEngine, so I thought there must
be some reason for that and tried CE first. However, elements.events.mouseover
is buggy - the event fires only when mouse stops moving. So, I was left
with EaselJS, and managed to get it to work, even easier than I thought
by using ButtonHelper class. More in my next post...
Feedback & Share
Milan Babuškov, 2013-05-08
Capturing mouse movement with Cocos2d-html5 and replacing default cursor
I decided to try to use Cocos2d instead of jQuery and DOM for my
next browser game. I find Cocos2d documentation confusing, and googling
around you are more likely to get Cocos2d-iPhone documentation that
simply does not apply for some stuff.
I spent a couple of hours trying to understand how to handle mouse
or if it is even possible. I found examples using Cocos2d-javascript
that worked fine, but using the same code with Cocos2d-html5 did not.
At one point I was close to conclude that mouse is not supported as
everything tries to emulate touch. However, this is not the case,
mouse handling works fine.
Currently (Cocos2d-html5 version 2.1.3), the best documentation is to read the file
CCMouseDispatcher.js in cocos2d/touch_dispatcher directory. In your
code, in layer object you can use onMouseMoved and other
methods found in this file. You might need to figure out the
parameters yourself. For example, onMouseMoved returns an event object which
has getLocation() function, which returns another object with x
and y properties. So, the code to draw a custom cursor would
be something like creating the sprite and then updating its position like this:
onMouseMoved:function (event) {
cursorSprite.setPosition(cc.p(
event.getLocation().x,
event.getLocation().y)
);
}
Now, this would give you two cursors. I tried setting the cursor for
the canvas element to none via CSS, but it did not work.
Another workaround would be to set a transparent 1x1 pixel cursor using
CSS like:
canvas { cursor: url('transparent-image.png') }
I'm yet to try if this works, but somehow I feel it won't. This is all
using Firefox 16 on Linux.
Feedback & Share
Milan Babuškov, 2013-05-07 Past posts