Friday, January 27, 2012

bounding rectangles 101

I'm very psyched to be doing the Global Game Jam for the fourth time-- all around the world people form small teams in order to make interesting games, all over one-48-hour weekend.

Something that comes up often in game programming is the question "did this thing hit this other thing?" Often, the easiest way of figuring that out is using "bounding rectangles", changing the question to the simpler-to-code "does the box corresponding to this thing's outline overlap the box corresponding to this other thing's outline?" (Even if you need to do a finer-grained collision detection, it's often more efficient to start with this question.)

But even with this simplification, it's not a trivial thing to code. If you code like I do, you'll be having two objects, each with an x,y coordinate for their top corner, and a width and a height (referred to now from w and h).  My class in (processing/processing.js) to represent that is something like this:

class boxish{
    float w,h,x,y;
    color c;
    
    boxish(float px,float py,float pw,float ph,color pc){
            x = px;
            y = py;
            w = pw;
            h = ph;
            c = pc;
    }
    
    void draw(){
        fill(c);
        rect(x,y,w,h);        
    }    
}

that lets me create a box, give it a color, and then ask it do draw itself.

So now what?

The first simplification of "do these boxes overlap?" can be "do these boxes overlap horizontally AND vertically"? Because two boxes could be around the same x-coordinate, but if one is way higher than the other one, they won't overlap-- and vice versa for the y-coordinate. By breaking down the problem this way, we're turning our 2 dimensional issue into a 2 1 dimensional ones... much easier!

The trivial code for this is

boolean overlapBox(boxish b1, boxish b2){
    if(overlapHoriz(b1,b2) && overlapVert(b1,b2)){
        return true;
    } else {
        return false;    
    }
}


Ok. Lets start with the Horizontal 1D problem. We have 2 line segments, and we need to know if they touch each other. There are 6 possibilities, outline here in this crude diagram:

I don't know about you, but my takeaway was this: there are more ways for two lines to overlap than for them not to... therefore, we're going to just test for the two cases where they don't - namely where both of line1's points are to the left of line 2's left or both the points are to the right of line 2's right.

So my code was:
boolean overlapHoriz(boxish b1, boxish b2){
    float b1left = b1.x;
    float b1right = b1.x+b1.w;
    float b2left = b2.x;
    float b2right = b2.x+b2.w;
    if(b1left < b2left && b1right < b2left) return false;
    if(b1left > b2right && b1right > b2right) return false;
    return true;
}


overlapVert() should be pretty obvious from that.

So that's it. I put together the following little test program that changes color when the moving box overlaps one of the static ones:


You can see the full psj sourcecode here.

Wednesday, January 18, 2012

a simple jquery slot machine effect

Update! This is now a proper github project with a lot of details filled in... More Information Here!


For work they wanted a "juicy" (I've been promoting use of that term for pleasingly physical or generally pleasant animations) way of showing a randomly generated amount of virtual currency assigned to the user. I suggested a slot machine-effect, and it came out really nicely, a widget with a very high "coolness to code complexity" ratio.

Here's another version of what I quickly came up with, click to spin!


The final product for work was a bit different, a single little rotating slot with graphical icons and more polish,  (including a nice fade in behind once the final amount was displayed). But for messing about purposes, I simplified the display, threw in a few extra windows, and made the results A B C D or F.

You can see the html, js, and css here.

There's very little too it, really: each slot consists of an outer class "slots" that provides the border and has a hidden overflow. Inside each slot is a (very tall) "wrapper", and then the js code adds a bunch of divs of class "slot", each as wide as the wrapper and each containing a random letter.  When it's time to let things "spin", we just animate the wrapper's margin-top property to a multiple (7) of the negative height of a single slot. Some of the secret sauce is the easing, "easeOutElastic" from the jQuery easing module... I wrote about that easing stuff earlier.

If the user clicks again, we repeat the process, adding in extra divs of class slot, and moving an increased seven times the height from where it was before. There are some little tricks going on here: we add more divs than we actually need because the elastic animation overshoots a bit (and of course, it's not really circular like a real slot machine would be), it took a while to realize that you should just move a small # of slots, and I added some randomness to the length of time of the animation, so it didn't all move in lockstep. It would be easy to tweak the timing so slots 2 and 3 started after 1, for a kind of 1....2...3! effect. (Another thing I added for this demo was the use of the "stop()" command... otherwise repeated spin clicks would have to wait until the earlier spins were fully settled. stop() has some arguments I missed when I first learned about it, they didn't come in handy here, but let you control if the element/animation queue finishes the pending animation(s) or just stops cold to start the new one. (Actually it turns out I needed to stop() the animation, including the parameter to jump to the final position, before reading the old position to set the new goal.)

Stuff like this is a great argument for jQuery/CSS UI engineers to err on the side of building things from scratch rather than relying on gluing together pre-existing bits. If I had only used other people's slideshow modules, rather than realizing it was a simple matter of wrapper divs, overflow:hidden, and animating margins, I wouldn't know enough to put this together... but it's really quite simple when you treat jQuery and CSS as the empowering technologies that they are.

BONUS PROTIP: This animation read the old margin-top in order to set the new one
jqo.css("margin-top"); //jqo is the jQuery object
That returns a value like "100px". To get rid of the "px" and treat that as an integer, parseInt works very well, it's designed to read numbers at the start of a string and then stop when it encounters non-digits:
var marginTop = parseInt(jqo.css("margin-top"), 10);
(The 10 after makes sure that we keep things in base 10, if the number string started with, say, a "0", strange  things might result.)
Of course after you've done your math you need to append the "px" again, but you know that already, right?

Thursday, January 12, 2012

on smaller frameworks

(This is a response to Gordon L Hempton's blogpost Javascript Frameworks Are Too Small)

Interesting article link you posted. Why don't we have as many layer of abstractions for web development? One answer might be, each of levels Queru describes is built on a REALLY reliable and well-engineered level beneath it, and there isn't that kind of solidity under JS/HTML5. But I think the other answer is: it's not necessary, at least for a certain kind of developer.

I can't even tell you how foreign I find your proclamation given the choice between two frameworks with equally well-written code, I would probably opt for the larger framework

There's a valid outlook that's the opposite of this: it says, I want to learn as little new as possible to get the job done, to minimize the mental load my tools are causing me. Toolkits with lots of abstraction often don't have good power/weight ratios; they're not much more expressive than more basic toolkits, but there's a lot more you new unique knowledge you have to keep in your head to use them properly (lest you become one of those Microsoft-y types, who can do decent stuff but have NO idea what's going on under the hood, or how to fix it when it goes wrong in a deep way.)

I think more abstract toolkits tend to program in nouns... "configure me correctly/learn which of my calls will do your bidding, and I'll do all the "tough work" and you can keep commanding on high rather than dirtying your hands in the trenches". But the cost of that comes in debugging, where suddenly the result of your bug is more likely to be farther away -- "physically" in the files, mentally in the abstraction -- than if you kept your toolbox nice and light and focused on the solving the problems that are actually a pain in the butt to keep resolving. (jQuery being one of the shining examples of awesomeness for the latter.)

I agree that "a larger amount of energy goes towards dealing with the frameworks involved, rather than the problem being solved" but not in the sense you mean: finding people who know the intricacies of a new stack, or training up people to get that knowledge, is the expense...

Friday, January 6, 2012

jquery animating background positions (and colors)

Short but sweet: "background-position" tends to be a compound kind of setting, with a separate value for x and y, but the single key. This means jQuery's default animation function can't smooth animate it, like it can't animate color transitions. But just like how there's a plugin to let you animate colors there's one for backgroundPosition as well. There's not much to it besides what the page says. I stuck copies of both on my "just in case the links go away" jquery file archive at https://kirk.is/m/files/.

Thursday, January 5, 2012

juicy in 2012: bouncy topicgrid

This is a work in progress for my day job, but I'm digging it so far: squares that jiggle on hover, then expand to twice the size when you "hold".


(Live demo from https://kirk.is/m/files/kirkdev/topicgrid/) These are all divs positioned absolutely with a containing div. The "shove the small blocks out of the way" routine our UX guy Marco was looking for was hard to wrap my head around at first. Say we're growing 0-0, doubling its height and width so it takes 4 spaces instead of 1, a net change of 3 spaces. We start by shoving the columns topped by 0-1 and 1-1 straight down, freeing 2 of the squares. We then shove 1-0 to the right, freeing up the final square. And to make room for 1-0, the column topped by 2-0 has to be pushed down. (But if the block we're growing is on the right side of the layout we change its position so that it grows to the left, and that changes which side our single column down is on.) It seems pretty simple (to me, now) when I write it out (3 groups of blocks to move: the 2 cols. underneath, the singleton off to the side, the single col. down to make room for the singleton) but I kind of had to sleep on it to get the general case.

(The other UI guy Ben pointed out the cool flexible zooming grid at  the Adidas homepage -- that looks like it was an even cooler challenge.)

The other fun and educational part was the "jiggle" when you hover the mouse over a block-- this creates a small juicy "toy" as you sweep your mouse across the whole area. My first idea was trying to use one of the bounce-y easings, but keep the block the same size. This did precisely nothing... I think the easings generally depend on multiples of the difference between two values like width/height or position so you can't "ease in place". I then tried the JQuery UI effect "bounce", but it assumes you have something that can be positioned "relative" on the page, and left the div stuck to the top left when it was done. So I rolled my own, using a series of animations (using the built-in linear easing instead of the default swing)- it animates to random x and y offsets, then animates to half the opposite of those values, then settles back to where it was.

This isn't perfected yet, but it's pretty good. I had to look into different techniques for restoring the squares...  I thought always stop()ing the animation would help, but that just got blocks stuck. So now it just adds the move onto the animation queues, but it works out, in part because things are pretty briskly paced.