zomgistania

Main page | About | Articles | Previous Posts | Archives

Monday, October 30, 2006

Racing games

I just uploaded my latest widget, called WidgetRacer to Opera Widgets.

It's a top-down racing/sliding game and it has a track editor too!


I've long been a fan of small top down racers like TurboSliders and Slicks'n'Slide and wanted to make my own sometime.

Well, there it is!


It lets you save and load tracks to the widget, to the disk so you can share them with others. The track editor is quite good. Unlike most editors in games like this, you can create the shape of the road yourself so you're not limited to pre-selected pieces of road.


I was also planning on adding an online track database kind of thing, but sadly the MySQL server on my linux box went nuts... I could've done it with text files too I guess, but I ditched the idea for now.

I'll implement it later for sure, though. It doesn't really require that much even with text files but some extra stuff to make sure the files don't get corrupted etc.


Another cool thing would be two player game on the same computer or over network.


2 players on the same computer is a possible option. I'm thinking about adding it in an update sometime, as it doesn't require much more than adding the keys... another thing is if the cars need to collide... that's gonna require some more work.



The thing is, however, that the game is made in JavaScript and uses the canvas element.... making it slow as heck on anything but a rather good PC... oh well, I'm considering remaking it in 3D in C# ;)


Kind of tired at the moment, so I won't be going into more details as I'm having trouble thinking... hehe



Oh yeah.

100th post! w00t!

Labels: , , ,

Monday, October 16, 2006

Canvas stuff

I've been lately experimenting a lot with the canvas element.

For those of you who don't know what this "canvas" thing I'm talking about is, it's a new element in HTML, supported by Firefox and Opera at the moment. You can use it to draw graphics and such, like in games.


The first thing I made, was an Asteroids clone.
Currently available in widget form from the opera widgets page, it's a pretty cool game, I might even say.

It's actually rather simple to draw different shapes and such with canvas... you just define the starting point and then it's a game of "connect the dots": just give it the points you want to draw lines to. Pretty simple stuff.

You can even do translations, rotations and scaling on the graphics, which might be expected from a vertex based renderer like DirectX. For example the asteroids are just defined as a few points, then stroked with a single command... they can be rotated as simply as calling a function and giving it the angle in radians.


The second experimental game is a Missile Command -style shooting game. Opera Command, as I call it, is also available from widgets.opera.com.

The non-widgetized version of it also worked on firefox... somewhat. Your own missiles wouldn't fire for some reason. Oh well, Firefox is so crappy anyway ;)



There's only one issue with canvas, though: JavaScript.

JavaScript is very slow compared to most programming languages which are usually used to make games. It seems that the canvas itself is okay rendering performance-wise, but the bottleneck is the scripting language.

Do a lot of math, like precise collision detection (say... pool), and you'll bog down everything. Opera's JavaScript engine is the fastest I've seen yet, and it's still slowing down when there's much action on the screen.

This leads to the fun part: optimization. Try to avoid every command.

An issue caused by slowdown of JS on slower machines cause another issue: the games run faster on other computers than others... this could be avoided if one introduced proper timing into the script.

That, however, would require even more calculations per frame... you'd need to take at least one new Date object per frame so you could calculate how long the last frame took... I haven't tried this yet, so I can't say for sure if it has a large impact, but considering that avoiding unnecessary things in JS is good...



The key in JS+canvas game dev: simplicity?

Take the explosions in Opera Command for example. There's no image involved or complicated shapes... only an expanding circle which is filled with a gradient. And it still looks pretty good!

I noticed a slight detoriation in the speed when I added the little missile graphics. I wonder if it would've been a better idea to just create them as lines instead of using a .png image...


It would seem that using images doesn't have much difference over using circles and paths and such if you look at the speed. For example in the Asteroids game, there were no images used in rendering and it still slows down a bit if there are lots of asteroids going around etc., Opera Command on the other hand has the little missile graphics and the city graphics being rendered.



So it seems to stand that the more going on -> the slower things will be. Well, this stands in every programming language, but the limit of what you can do comes very quickly in JavaScript, especially on slower machines.

Labels: , , ,

Wednesday, October 04, 2006

Sounds are problematic, splitting images is not

In my latest widget, the Reaction Game, I wanted to have some sounds.

The basic idea of the game is that some lights will turn on and you have to click on them... sometimes you may have to click on the same light more than once. This might be a bit confusing, as when you click on the light and it doesn't turn off you might think "wtf, why did it stay on?"

This is why I wanted to add different beep sounds for each of the lights.

There are few options to do it:
- Use a .swf file which can play sounds (See my post here)
- Use the object tag
- Use the embed tag
- Use the Audio object in JavaScript


The .swf file which can play sounds...
This one used to work. I don't know if it was Opera 9.01 or 9.02 which broke the functionality, though. It still works outside widgets, though.

The object tag...
works outside widgets but inside widgets causes them to freeze.

The embed tag...
does the same as the object tag

The Audio object...
the same as the two above


There are so many alternatives, yet none works. Why? Get to fixin' it, Opera Software!



In the other news, I've again released a bunch of new widgets.

I'll describe one here because it has a pretty intresting approach to doing some things...

The Puzzle Creator widget lets you create a jigsaw puzzle of any picture on the internet. You just give it the URL of the image and stuff like how many columns and rows of pieces you want.


As you might know, JavaScript doesn't really have any image manipulation functions, so you can't just take an image and split it in smaller pieces. The trick employed here is the CSS clip property!

You can use the clip property in CSS to define the area of an element you want to display... so, to get small pieces of an image we just calculate the size and position of the part we want to show and use the clip property. Pretty neat, even if I say so myself.

This, however has a small problem again... if you clip an image, the image's width and height will still be the same and the parts outside the clip area won't show but they are there, so the area inside the clip rectangle will be offset from the corner.

To fix this, the widget just calculates the offset and saves it to each piece with setAttribute.


For those of you who aren't using Opera (why?!), here's a non-widget version of the puzzle creator


There might be one additional approach to doing this with JS. Both Firefox and Opera have an element called "canvas". This can be used to draw graphics, a bit like GDI for example.

As I don't have much experience in using the canvas, I can't say this for sure, but you could just put the image on the canvas and draw white on top of parts you want to hide. I'm pretty sure you can use images on the canvas like that, so it should be quite possible.

With this approach, however, you would have to code in various things like click events and such. When using separate html elements, changing the places of the pieces is as simple as changing different left and top attributes.


That's all for now.

Labels: ,

Sunday, October 01, 2006

<select> boxes

I'm sitting in the #Javascript channel in Quakenet at IRC. Pretty often you see someone who wants to something to happen when you choose an item from a select box...

"I want to show some fields if user selects X from my list"

"I want to have 3 <select> boxes and when you choose 1 there will come a new select box.. how can I do that?"

etc.

I made a quite simple sample script of this.


I thought it might be a good idea to explain it a bit, though.

Starting with the HTML code:

the basic idea is to have a select element and give it an ID so we can easily use it in JavaScript. In the example, the select elements ID is "selector".

Then we need something to show and hide depending on what's selected: in the example, a couple of div elements. Yet again, we should give these some IDs so they can be easily accessed from JS... in the example they're called "right_1" and "right_2".

These divs are also hidden by default using the CSS definition "display: none".


In the select element, we use the onchange event to call our JavaScript function. As you can see from the HTML code, onChange="ShowRight()"


Now let's look at the JavaScript function...

First, we use document.getElementById() function to find the select element. We use .selectedIndex to find the numeric index of the item which is currently selected... note that the first one is 0, not 1.

We save this index to a variable called "selected".


After this we hide the two divs we have. This is because the user might have selected something from the select already and one of the divs might be visible.


Then we have a switch statement. This is used to do something depending on what the value saved in selected is.

As you can see, if the value is 1 the code uses document.getElementById() to find right_1 and then sets it's CSS value display to "block" and if the value is 2, it shows the right_2 element instead.



Pretty simple stuff, isn't it?

Labels: ,