Web Applications Blog

The 'Opera-2dgame' Canvas Context

, , , ,

Since we added support for the canvas element in Opera 9 tp1, we have also supported a custom context on the canvas, named "opera-2dgame". As suggested by the name, this context has functionality specifically geared toward game authoring. Let's have a quick look at what we can do with it. However, please remember that this functionality is still experimental, and that the interfaces may change at any time before a final version of Opera is launched.

Using the 'opera-2dgame' context

To use the custom context, you simply call the 'getContext' method on the canvas, with the argument 'opera-2dgame', much the same as you would do if you were working with the regular canvas.:

// get the first canvas element on the page
var canvas = document.getElementsByTagName('canvas')[0];
// get the game context:
var gctx = canvas.getContext('opera-2dgame');

Pixel-by-pixel manipulation using getPixel() and setPixel()

From reading the canvas developers mailing list it seems that one of the more requested features is the ability to read and modify pixels on an individual basis. The opera-2dgame context has just that.

The getPixel() method

If you want to read a pixel value directly, this is achieved by using the getPixel method, which takes two integer arguments, representing the coordinate for which one wants to get the color value:

// Read the pixel at 0,0
var myPixel = gctx.getPixel(0,0);

The value returned by getPixel is a string, and is returned in one of two forms:

  1. If there is alpha information in the pixel, the value returned is on the form rgba( r, g, b, a )
  2. If the pixel is fully opaque, the value is on the form #rrggbb

getPixel() and security

For the security-concious out there, Opera enforces a same-origin policy on the canvas: Trying to call the getPixel method on a canvas element that contains data from a third-party server (that has foreign content) will raise a SECURITY_VIOLATION error. For what it's worth, the same restriction is enforced on the toDataURI method on the HTMLCanvas interface.

A canvas element is considered to have third-party content if drawImage has been used with an HTMLImageElement as an argument, and this image is from a third-party server , or if drawImage has used with a HTMLCanvasElement as argument, and this HTMLCanvasElement has previously been determined to contain third-party content.

setPixel()

While getPixel on its own has some meaning, the real power is revealed when we add the setPixel() method. The method takes three arguments: The x and y coordinates, represented as integers, and a string representing the color, represented as a CSS color.

// set the pixel at 32,24 to the value 'rgba(255,127,0,0.5)'
gctx.setPixel(32,24,'rgba(255,127,0,0.5)');

// set the pixel at 32,25 to the value '#f33'
gctx.setPixel(32,24,'#f33');

// set the pixel at 32,26 to the value 'red'
gctx.setPixel(32,24,'red');

Examples

Here are a few examples of using the getPixel and setPixel methods to perform image manipulation in much the same ways filters in popular graphics application works

Collision detection

Indeed. The opera-2dgame context does collision detection as well, and makes it really simple for you: The checkCollision method on the 2d-game context takes an x and y value as arguments, and when called, will check whether the given coordinate is within the currently open path on the '2d' canvas context. The checkCollision() method returns 1 if the point is within the open path, and 0 otherwise. The checkCollision method does not take any translatation on the regular '2d' context into consideration; the x and y values are relative to the top left corner of the canvas.

// draw a rectangle from 0,0 to 100,100
// ctx and gctx are previously created references to the
// 2d context and the opera-2dgame contexts on a canvas element.
ctx.beginPath();
ctx.fillStyle = "blue";
ctx.beginPath();  
ctx.lineTo(120,0);
ctx.lineTo(60,90);
ctx.lineTo(0,0);
ctx.fill();

// Output '1', since the point 60,25 is inside the open path
alert( gctx.checkCollision(60,25) ); 

// Output '0', since the point 150,150 is outside the open path
alert( gctx.checkCollision(150,150) ); 

Examples

We've prepared two small checkCollision() examples for you to look at:

  • Click the blue triangle - when clicking the blue triangle, you should be told whether you've clicked on the triangle or somewhere else.
  • Hit the ball - A little "How to get RSI ASAP"-game where the aim is to click the ball.

Optimizing canvas performance using locking

Finally, if you write high-performance canvas applications, such as games, you might want more control over the canvas redraw. The opera-2dgame context provides you with ultimate control using two methods:

lockCanvasUpdates( bool Lock) takes a boolean value as argument. When this function is invoked with the argument , updates on the 2d canvas context are locked. When a canvas is locked for updates, you can perform operations on it as you normally would do, but the updates will not update the display of the canvas. The advantage of this is that if you need to do multiple, possibly complex operations on the canvas, such as display a frame in a game with all heros, monsters, backgrounds and fluff, you won't waste any time rendering this to screen.

When you are ready to render your frame and update the canvas, you first call the lockCanvasUpdates(false) to allow updating the canvas. Next, you call the updateCanvas() function to force the canvas to repaint, and you relock the canvas again afterwards, using lockCanvasUpdates(true) as illustrated below

// We start by simply locking the canvas:
gctx.lockCanvasUpdates(true);

function renderFrame(){
  /* 
    First, lots of code rendering a frame
    in a complex scene 
  */
  // When we've rendered everything, we refresh the canvas:
  gctx.lockCanvasUpdates(false);
  gctx.updateCanvas();
  gctx.lockCanvasUpdates(true);
}

These additional methods should provide authors with the means neccessary to write graphics applications and high-performance games, in widgets or on web sites. Use your creativity.

Welcome to Web ApplicationsA Short Story about the Long Tail

Comments

Aux Wednesday, March 29, 2006 3:47:37 PM

That's cool! I'm developing Tetris clone as Widget, so this info is very useful!

RamūnasRamunas Wednesday, March 29, 2006 6:02:53 PM

A lot of useful info, thanks

João EirasxErath Wednesday, March 29, 2006 6:04:52 PM

beautiful!!! cheers

Unregistered user Wednesday, March 29, 2006 6:06:05 PM

Johnnyappleseed writes: This is awesome stuff, Virtuelvis. Love the demos.

Unregistered user Wednesday, March 29, 2006 7:30:50 PM

Papuass writes: Are there any plans on standartisation these canvas functions so thet they work in other browsers, too? Will you adopt other functions from Mozilla, Safari or IE developers? Is there a coordinated work?

Unregistered user Wednesday, March 29, 2006 10:53:18 PM

Anonymous writes: This is very cool! I hope to get my little canvas rpg working in opera...

Jan StandalThink Thursday, March 30, 2006 7:08:20 AM

The canvas element is described in the Web Applications 1.0 spec (which is also known as HTML5) from WHATWG. I would expect these additions to be added there. /t

Anne van Kesterenanne Thursday, March 30, 2006 1:02:06 PM

We hope to submit a proposal to the WHATWG soonish, yes.

Jakub81 Thursday, March 30, 2006 3:28:35 PM

Nice, but collision detection isn't really collision detection, except for 1px objects like mouse clicks... (?) though it may help in writing the function that detects a collision of 2 rectangles etc.

Unregistered user Wednesday, April 12, 2006 4:13:01 AM

jK writes: It seems that the updateCanvas()-function is buggy. If I render much objects in one frame, the function only draws a piece of the commands I put in :-/ example: h*t*t*p://home.arcor.de/jk3064/opera/canvas.html

Unregistered user Thursday, April 27, 2006 5:25:44 PM

WagoOn writes: I thing that GREAT IDEA is color selection from canvas. I mean something like color selecting in photoshop, just click in the canvas!

Smir Thursday, June 8, 2006 2:57:34 PM

There are problems, if you change the size of the canvas after it has been created.

If I load the blue triangle and increase the width of the canvas, I can click on the triangle and still get the message "You clicked outside the triangle":

Goto
http://oxine.opera.com/gallery/canvas/2dgame/triangle.html

enter this in the address bar:
javascript:void(document.getElementsByTagName('canvas')[0].style.width = "600px");

click on the right side of the triangle.

Arve Bersvendsenvirtuelvis Tuesday, June 20, 2006 1:37:09 PM

Smir: Duly noted. This seems to be a genuine bug.

Unregistered user Tuesday, June 20, 2006 11:18:12 PM

Anonymous writes: The image processing demos are interesting. After clicking on an image, then clicking reset, the restored image looks terrible: it's all blocky, sort of like an overcompressed JPEG. Reloading the page doesn't restore the orignal image either. I have to close the tab and revist the page fresh.

Benjamin Joffe Friday, June 23, 2006 8:32:24 AM

I would love to see the following methods implemented, a game I am working on would benefit greatly from them and I'm sure others would to.

gctx.pathArea();
This would return the area of the current path, if no path is created then it would return 0.

gctx.clipArea();
This would return the area of the current clipping path, if no clipping path was in effect then it would return the area of the canvas.

Arve Bersvendsenvirtuelvis Friday, June 23, 2006 9:02:03 AM

Benjamin: Would you mind proposing this on the WhatWG mailing list, to encourage some proper discussion of the subject?

Kevinin Wednesday, June 13, 2007 2:06:28 AM

I've written a simple workaround for FF to also be able to use setPixel and getPixel with the '2d' context. http://kweb.wordpress.com/2007/06/13/extending-2d-canvas-with-getpixel-setpixel-methods/

bfattori Tuesday, March 11, 2008 4:01:14 PM

This is fantastic. I hope that FF and Safari adopt something like this, as it would push my concept forward:

http://code.google.com/p/renderengine

The aim of this project is to create a fully reusable game programming API for javascript. Since the canvas context is only one of the supported contexts (but my favorite one by far) I hope to see this approach adopted.

Altareum Friday, December 5, 2008 10:59:47 PM

(sorry, but my english is very bad)..

I'm searching for a way, to detect, multiple selection with the onclick.
I mean, if i have 2 triangles, can detect when the user, click 1 or another.

Have any idea?


Thx
Altareum.

Write a comment

New comments have been disabled for this post.