Enough Fun and Games

Ok, So I am taking a short break from the game to do some real work. Sort of.

In learning Javascript, I decided it would be worth my while to learn some jQuery as well. Turns out it is super-easy and useful for making simple applications that have "real work" uses.

I developed two small tools that could be used in a number of ways. One is just a big-old table of contents style drop down, complete with link descriptions.

The other is what I call a "workflow" that could be used for giving instructions or even trouble-shooting common issues. Check it out here.

Both are easily adaptable and open source. So feel free to pilfer the code. Feel free to ask me questions if you need help using it.

Table of Contents

For this little app, I just needed a list that I could easily add links to and would fold itself up, so there wouldn't be too many on a page to look at at once. You can just look at the relevant section and ignore the rest.

First, each "category" is listed inside  list tag with class "slide". Then underneath, we create a list of links with class "articles". You can make unlimited categories.
 
<ul class='slide'>
<li><h3>Category 1</H3></li>
    <ul class="articles">
 +Each line is split at the plus
 +type "#plus" if you want to actually see a plus sign as text
 +It automatically parses addresses as links that are listed with http:
 +the script parses out the part after "Description:" for the mouseover
 +download the code here! http://games.codeandcompose.com/WorkApps/sourcecode.zip
                Description:The best code ever written! Or not.
    </ul>
... 

The app splits each line in the "articles" list by the +. Then it creates a link with an address (if there is one starting with http:// or https://). If there is a description (split at "Description:"), that will show up when you hover.

There is a tiny cosmetic glitch with the hover descriptions. I haven't yet come up with a great fix, but it's not too noticeable.

The string parsing was pretty simple. It uses some regular expressions and Javascript string.replace() function. After breaking the strings, it puts them into list elements and links (when used).

 
$.fn.extend({
    stringSplitToList: function() //this function parses the html body into a list for the jquery
    {
        var htmlList = '', aclass = 'none';
        $.each($(this).html().split('+'), function(i, v) {
            v = v.replace(/#plus/g,"+");//put plusses back in
            var tempSplit = v.split("Description:");
            v = tempSplit[0];

            //makes sure the description not undefined.
            var description = (tempSplit[1]) ? tempSplit[1] : "No description."; 

            if (v.match(/(https:\/\/|http:\/\/)\S+/igm)) {
                var alink = v.match(/(https:\/\/|http:\/\/)\S+/igm)[0];
                var title = v.replace(alink,"");
                if (title.match(/\*/gm)){
                    title = title.replace("*","");
                    aclass = 'internal';
                } else if (title.match(/\^/gm)){
                    title = title.replace("^","");
                    aclass = 'archive';
                } else {
                    aclass = 'none';
                }
                htmlList += '<li><a href="' + alink + '" class="' + aclass + '">' + title + '</a><div class="des">' + description + '</div></li>';

            //handle categories header
            } else if (v.match(/(href=)\S+/igm)) {
                var alink = v.match(/(href=)\S+/igm)[0];
                var title = v.replace(alink,"");
                alink = alink.replace("href=","");
    
                if (title.match(/\*/gm)){
                    title = title.replace("*","");
                    aclass = 'internal';
                } else {
                    aclass = 'none';
                }
                htmlList += '<li><a href="' + alink + '" class="' + aclass + '">' + title + '</a><div class="des">' + description + '</div></li>';

                //handle categories header
                } else {
                    htmlList += '<li><div class="category">' + v + '</div></li>';
                }
        });
        $(this).html(htmlList);
    }
});

Each link can also be marked as "internal" with a * or "archived" with a ^. You can even use internal links marked by href=

Just call this line once the page loads and it parses the text for you.

$('.articles').each(function(index){$(this).stringSplitToList();});

Workflow App

The workflow app can take very complex paths. By following the formula in each js file, you can add unlimited questions and answers. As the user chooses their answers, links, pictures and tips are given to help them out. The logic can be created to direct to a certain path based on previous answers form one or multiple questions.

I used it to make a wi-fi router trouble-shooting guide. The example given on this website is just for fun though.

Here is a graffle showing how the questions are programmed.



Each question is loaded in the following format:

addQuestion(1, //the question number
         //the question
    "This is workflow 1. Use this workflow?",
        //answer options (as many as you want)
    ["Maybe","No","Yes"],
        //answer direction, either a question number or LOGIC or RESET
    [1,"LOGIC",1],1, // the extra number is default
        //tips text
    "This area will show helpful tips. Or not...",
        //image urls (as many as you want) or null
    ["image1.png","image2.png"],
        // url and text for helpful links
    [{"url":"http://tagsounds.com","title":"A Link to TAGSOUNDS.COM"}],
       // callback function for when the direction of an answer is LOGIC
    function(){
        if (AA[0] === "Red"){
            nextQuestion(201);
            return;
        } else loadWorkflow("workflow2.js");
    }
);

If you like it, or would like to know more about how to adapt it for your needs, please contact me using the contact form at tagsounds.com.


INPUT (Click me! Click me!)

One of the most important elements of game-play is user interaction.

So many RPG games are great tactical games, but lose the sense of real-time enjoyment while bouncing through menus. An early prototype of my game was menu centric. But as I make some mini demos, I'm trying to limit the amount of time spent in the menus in favor of faster input choices.

For this demo, there is no need for a menu. One click on a character selects him and then click the enemy and he attacks. OR, click and drag to aim the projectile, release to fire. Click twice on the character (not double-click for reasons I will explain) and then click an empty space to move them.

I'd like to keep it setup in a way that may be ported to touch screen devices. I imagine that will introduce new challenges. Perhaps I'll learn Objective-C first and make an app... ?

Anyway. Step one is capturing the click. Since everything is done inside the canvas, we use the following code:

window.onload = function (){
    var canvas = document.getElementById("gamewindow");
    document.getElementById('gamewindow').onmousemove = moveHandler;
    document.getElementById('gamewindow').onmousedown = clickHandler; //onclick is too slow for timing
    document.getElementById('gamewindow').onmouseup = clickReleaseHandler;
    document.onkeypress = onkeypressHandler;
}
function moveHandler(event){}
function clickHandler(event){}
function clickReleaseHandler(event){}
function onkeypressHandler(event){}
Notice that I used mousedown instead of onclick. This is important for calling functions quickly so that when the player tries to synchronize with the music, it is more accurate. Plus we can catch the mouseup event separately. The downside, is that differentiating click from double click is harder, so we just don't do it!

Each event listener is directed to a handler function. Now we have to do, you know, logic.

Unlike normal interactive elements, there are a few challenges to overcame when dealing with a live game environment. Starting with the fact that everything moves. Thus, step one is finding out what was clicked.

Or as I quickly learned, the FIRST step is to offset your click location to account for the placement of the canvas and scrolling...

function clickHandler(event){
    // cache the time/location of the click
    clickTime = audioctx.currentTime;

    event = event || window.event;
    var scrollX = window.pageXOffset || document.body.scrollLeft;
    var scrollY = window.pageYOffset || document.body.scrollTop;
    clickX = event.clientX + scrollX - xoffset;
    clickY = event.clientY + scrollY - yoffset;

    var gclick = guyClicked(clickX,clickY,"Allies",true);
}

function guyClicked(X,Y,dic,mustBeReady){
    var dict = activeGuyDict[dic];
    for (var guy in dict){
        if (!(X < dict[guy].pos.x + dict[guy].bounding.x || X > dict[guy].pos.x + dict[guy].bounding.x + dict[guy].bounding.w || Y < dict[guy].pos.y + dict[guy].bounding.y || Y > dict[guy].pos.y + dict[guy].bounding.y + dict[guy].bounding.h)){
            if ((mustBeReady && dict[guy].ready) || !mustBeReady) return guy;
            //character must be ready if "mustBeReady" is true
            else return null;
        }
    }
    //no guy was found
    return null;
}
If you don't feel like ripping through that IF statement in guyClicked, here's the rough explanation. It's a beautiful use of NOT OR logic. We need to see if the click occurred INSIDE the bounding box for the character. If the box is 50x100 at point (200,130), we see if the x was between 200 and 250 and if y was between 130 and 230, right?

We could setup the logic to see if x > 200 AND x < 250 AND y > 130 AND y < 230...

OR

... we could check if the click falls OUTSIDE the parameters, and use NOT OR. Only one condition must be true for the whole thing to fail. Not sure if it matters here, but this is useful if you are comparing BOXES to look for overlap.

For my game, we also check to see if the character is "ready" before selecting. Now onto the real tricky logic.

First click down gets the aiming out. Then release to choose an enemy. Then click an enemy or click the good guy again. Or click another guy to change the selection. Then click a spot to move. Or if an enemy was selected, click again to time the attack. Or, um... what else can you do with just a click? It gets complicated fast.

I found that (although counter-intuitive) it works best to write the logic backwards. Start with the most specific scenario first and work backwards through input order. That way, the handler can check for the specific scenarios and bail, or move on.

In plain text it looks like this:
  • Check to see if a selected character is waiting to move.
    • If a character was clicked, change focus
    • If an empty space was clicked, move
  • Check to see if an attacking character is "PRIMING".
    • Was the appropriate enemy clicked?
  • Check to see if an enemy must be selected to attack.
    • Did you click an enemy?
    • If a character was clicked change focus
  • If none of those criteria are met, select the clicked character.
   
for (var pg in activeGuyDict.Allies){
    // check to see if a character needs to move
    if (activeGuyDict.Allies[pg].moveForm){
        activeGuyDict.Allies[pg].moveForm = false;
        activeGuyDict.Allies[pg].selected = false;
        colorWheel.reset();
        //need to check if the space is occupied by the other character
        if (guyClicked(clickX,clickY,"Allies")) continue;
        activeGuyDict.Allies[pg].formation = {"name":"Formation","pos":{cx:clickX,cy:clickY},"halo":{cr:0,r:5}};
        activeGuyDict.Allies[pg].action = "FORMATION";
        activeGuyDict.Allies[pg].target = activeGuyDict.Allies[pg].formation;
        return;
    }
       
    if (activeGuyDict.Allies[pg].animation.name != 'PRIME') continue;
    if (!activeGuyDict.Allies[pg].attackTarget) continue;
    else var primeClick = guyClicked(clickX,clickY,"Enemies");
    if (!primeClick) continue;
    if (primeClick === activeGuyDict.Allies[pg].attackTarget){
        var cT = clickTime; //un-cache the click time
        activeGuyDict.Allies[pg].setAnim('ATTACK',cT);
     
        //this code determines the power, based on the timing
        var sync = 0;
        var hbl = secondsPerBeat / 2; //half a beat length
        if (cT - lastBeatTime < nextBeatTime - cT) sync = Math.round((cT - lastBeatTime)/hbl * 50);
        else sync = Math.round((nextBeatTime - cT)/hbl * -50);   
        //calculate the power/damage here
        var power = activeGuyDict.Allies[pg].power(sync);
        activeGuyDict.Enemies[activeGuyDict.Allies[pg].attackTarget].takeHit(power,pg);//determine the damage taken from the hit
        clickTime = null;
        return; //don't do anything else with the click
    }
}//end FOR loop
   
if (selectThis === "ENEMY"){//picking an enemy to attack
    var gc = guyClicked(clickX,clickY,"Allies",true);
    var g = findSelectedChar();
    if (gc) { // a good guy was clicked... handle it
        if (gc != g){ //a different ready character was selected..switches focus
            selectThis = "";
            activeGuyDict.Allies[g].selected = false;
            activeGuyDict.Allies[g].action = '';
            var cT = clickTime;
            activeGuyDict.Allies[gc].selected = true;
            colorWheel.newSC(gc);
            selectThis = "AIM";
            activeGuyDict.Allies[gc].setAnim('AIM',cT);
            activeGuyDict.Allies[gc].action = 'ATTACK';
            mouseDown = true;//keep track of the mouse state
            return;
        } else if (gc === g) { //same character was clicked... moveForm
            activeGuyDict.Allies[g].moveForm = true;
            //cancel ATTACK action
            selectThis = "";
            activeGuyDict.Allies[g].action = "";
            return;
        }
    }
    var e = guyClicked(clickX,clickY,"Enemies");
    if (!e) return; //make sure an enemy was clicked
    if (activeGuyDict.Allies[g].action === 'ATTACK'){
        activeGuyDict.Allies[g].ready = false;
        activeGuyDict.Allies[g].selected = false;
        colorWheel.reset();
        activeGuyDict.Allies[g].target = {"name":e,"pos":activeGuyDict.Enemies[e].pos,"halo":activeGuyDict.Enemies[e].halo};
        selectThis = "";
        colorWheel.reset();//close the color wheel
    } else if (activeGuyDict.Allies[g].action === 'TAUNT'){
        activeGuyDict.Enemies[e].taunted(activeGuyDict.Allies[g].pos,activeGuyDict.Allies[g].halo);
        activeGuyDict.Allies[g].animation.name = 'TAUNT';
        activeGuyDict.Allies[g].selected = false;
        colorWheel.reset();
        selectThis = "";
    }
    return;
}
//see if a ready guy was clicked
var gclick = guyClicked(clickX,clickY,"Allies",true);
if (gclick){
    var cT = clickTime;
    activeGuyDict.Allies[gclick].selected = true;
    colorWheel.newSC(gclick);
    selectThis = "AIM";
    activeGuyDict.Allies[gclick].setAnim('AIM',cT);
    activeGuyDict.Allies[gclick].action = 'ATTACK';
    mouseDown = true;//keep track of the mouse state
}
This is the mouseup handler. It only pays attention if the player is holding the mouse down to "AIM". Thus avoiding unnecessary event functions.
function clickReleaseHandler(event){
    // cache the time/location of the click
    if (selectThis != "AIM") return;
    clickTime = audioctx.currentTime;  
    event = event || window.event;
    var scrollX = window.pageXOffset || document.body.scrollLeft;
    var scrollY = window.pageYOffset || document.body.scrollTop;
    clickX = event.clientX + scrollX - xoffset;
    clickY = event.clientY + scrollY - yoffset;
            
    var g = findSelectedChar();
    var gc = guyClicked(clickX,clickY,"Allies");
    if (gc === g) {
            selectThis = "ENEMY";
            activeGuyDict.Allies[g].clearAnim();
            mouseDown = false;
            return; //bail
    } else {
        //they released on the aimed area
        var cT = clickTime;   
        var sync = 0;
        var hbl = secondsPerBeat / 2; //half a beat length
        //click is closer to last beat
        if (cT - lastBeatTime < nextBeatTime - cT) sync = Math.round((cT - lastBeatTime)/hbl * 50);
        else sync = Math.round((nextBeatTime - cT)/hbl * -50);//click is closer to next beat
        //click was before last beat (in case the beat changes between click and frame)
        //if (cT < lastBeatTime) sync = 50 - Math.round((lastBeatTime - cT)/hbl * 50);
        var power = activeGuyDict.Allies[g].power(sync);
        clickTime = null;

        //create the projectile
        projectiles.add("wave",activeGuyDict.Allies[g].pos,clickX,clickY,power,8,500,activeGuyDict.Allies[g].color);

        selectThis = "";
        activeGuyDict.Allies[g].ready = false;
        activeGuyDict.Allies[g].selected = false;
        activeGuyDict.Allies[g].setAnim('ATTACK',cT);
        activeGuyDict.Allies[g].target = null;
        mouseDown = false;
        return;
    }
}
As always, feel free to steal my code. Just let me know how you are using it! I'm curious to know how and if anyone finds this code useful!

And as promised, here's a link to the demo!

Instructions:
  • CLICK and DRAG from a character to shoot a projectile. They will not do damage, but different colors will have different effects,
  • PRESS Z or X to change the color of a character after he is selected.
  • Just CLICK a character once to select him, and then click an enemy to attack. The character will chase the enemy. You MUST CLICK the enemy once he has arrived in order to initiate the attack. Try to time it with the pulsing to do extra damage.
  • CLICK the selected character again, and then click an empty space to move him.
  • No damage indication is given, just keep attacking, and the enemies will eventually disappear.

Color and Dissonance

So what exactly is this game concept I keep mumbling about?

Well, here's part of the picture: You are immersed in a world with a mysterious energy force. Not much is known about it except two things. First, it's great for making powerful machines and weapons. And when it is harvested, horrifying and dangerous spirits are released.

Naturally, along your quest, you must face these spirits to survive. But you can't just beat them to oblivion like normal RPG monsters or zombies. They have to be "in phase".

As a composer, I decided that I should make a game that fit my specific knowledge and skill set. Thus, music and sound had to be solidly integrated into the game play. I'll get more into the music side later, but there is an underlying function of music in the battles as well.

Imagine each spirit is assigned a "note" or frequency. In addition to fighting them, you can also blast them with another "note" using the wave projectiles we created here. Depending on the "interval" between the notes, a different effect is achieved.

For those of you not familiar with music theory, this gets a little intense. And since I want the game play to be inclusive, I had to come up with a visual representation. So why not color each note?

This presented me with more of a challenge than I had expected. HOW do you color all 12 notes?

Many people have tried to color the scale for educational purposes, but usually focus only on a 7 note scale. With Roy G Biv, that works out nicely. But I had to get a little more creative.

Since the effect of the interval will be based on its "dissonance" or "consonance", I decided to match a  color wheel using the Circle of Fifths. If you know what I'm talking about, see the diagram. If not... um, well... take a music class.
The adjacent notes are all an interval of a 5th. Which is consonant. As you move around the circle, away from one note, the dissonance increases. For example, C is a semi-tone from B and a tri-tone from F#... very dissonant. This, similar colors blend, opposites, not so much.

For game play purposes I grouped them like this:
Unison (same note) will heal the enemy.
5th is consonant, so no effect.
2nd (whole-tone) will have a disruptive effect, like stopping the enemy for a moment.
Minor 3rd will have a positive effect, like speeding up the enemy.
Major 3rd will have a negative effect, like slowing.
Semi-tone and tri-tones are so disruptive they will actually change the note of the enemy.

The math for this works out really well too. The HSL color mode has 360 hues. That means the intervals can be determined by subtracting the color hues. For example, if C=150 and A=240, the difference, 90, represents a minor 3rd.

Now, it would be no fun to let each character have access to all 12 notes. So they get a "key palette". Basically, a set of notes that are available during battle.

I had to add some properties to my good guy object:
this.color = 150;//may be unnecessary = this.palette[0];
this.palette = [150,210,270,120,180,240,300];//an array of the colors available
this.changeStep = function(step){
    this.palette.rotate(step)
    this.color = this.palette[0];
    //return this.color;
};
The changeStep() function is called with an interval so the character can move through his palette (currently by pressing Z or X). What is palette.rotate()? A handy little method added to the Array.prototype that pushes items around the array in order. There are other methods of doing this here... but I liked this the best.
Array.prototype.rotate = (function() {
    return function(inc) {
        for (var l = this.length, inc = (Math.abs(inc) >= l && (inc %= l), inc < 0 && (inc += l), inc), i, x; inc; inc = (Math.ceil(l / inc) - 1) * inc - l + (l = inc))
        for (i = l; i > inc; x = this[--i], this[i] = this[i - inc], this[i - inc] = x);
        return this;
    };
})();
Then of course, we need to know when the projectile hits anything. So while we check for collisions between the enemy and other obstacles, we also call the projectile.HIT() method below. Now these waves don't dissipate upon hitting something, in fact they pass right through. So what's the best method for determining collisions?

Unlike collisions that ricochet, we don't need any fancy vector math to get the angles or energy transfer. All we really need to know is how close the hit was.

I decided on a simple formula for this. Once the collision is detected, we keep track of the exact distance between the center of the enemy and the center of the projectile. Then, when the distance starts to increase, we record the closest point and call the appropriate function for the enemy's reaction. That distance is passed to help determine the power (effectiveness) of the wave. This code is part of the "projectile" object constructor.
this.HIT = function (Epos,Ehalo,Ename){
    var dis = getDistanceSq(this.pos,Epos);
    if (dis.ds > (this.halo.r+Ehalo.cr)*(this.halo.r+Ehalo.cr)) return false;//not close enough
    //have it check to see if it has reached the closest location
    if (!this.hitList[Ename]) {
        this.hitList[Ename] = dis.ds;
        return true;
    }
    if (this.hitList[Ename] === "HIT") return false;
    // they have already hit...is it getting closer or farther?
    if (this.hitList[Ename] >= dis.ds) { //closer
        this.hitList[Ename] = dis.ds;
        return true;
    } else {
    // use the closest distance and calculate damage
        //takewave is the call that tells the enemy what to do with the "damage"
        activeGuyDict.Enemies[Ename].takeWave(this.mass,this.hitList[Ename],this.color);
        //remove the enemy from the list so he isn't hit again!
        this.hitList[Ename] = "HIT";
        delete this.hitList[Ename];
        return true;
    }
};
this.hitList = {};

// This is the helper function to get the squared distance 

function getDistanceSq(a,b){ //for when the square will do, to save energy rooting it...
    var x = b.cx - a.cx;
    var y = b.cy - a.cy;
    var ds = (x*x)+(y*y);
    return {ds:ds,x:x,y:y};
}
getDistanceSq() is a handy little function that uses ol' Pythagoras, but returns the distance squared (and the x and y vector) as an object. By using the square for comparison, we save the trouble of using a costly Math.SQRT().

One more blog post on the click cycle for battle mechanics, and then a DEMO! Yay! It will be playable, however without sound. And it won't be hard since you can't die yet... (one thing at a time).

Projectiles as Javascript Objects

In my game, like many games, there is a chance to throw, shoot, fling or otherwise propel something hazardous at your enemy.

I'll get more into the specific game mechanics in the next post. For now, we'll just focus on aiming and firing "something".

I chose to treat each projectile as a separate entity, just like the characters and enemies. However since there are an unknown number of projectiles coming and going at any time, they don't need names. Thus we use an array to collect them.

The nice thing about Javascript objects, is that we can make them do whatever we want. I decided to make a list object that not only keeps the projectiles, but adds and removes them thus:

var projectiles = {
    list:[],
    add : function (type,pos,x,y,mass,speed,range,color){
        var newP = new projectile(type,pos,x,y,mass,speed,range,color);
        newP.parent = this;
        this.list.push(newP);
    },
    remove : function (p){
        for (var i = this.list.length - 1; i >= 0; i--) {
            if (this.list[i] == p) {
                this.list.splice(i, 1);
                return;
            }
        }
    }
}

Then I created an object constructor for the projectiles thus:
function projectile(type,pos,x,y,mass,speed,range,color){
    this.parent = null;
    this.type = type;//wide, dart, explosive...etc
    this.pos = {"cx":pos.cx,"cy":pos.cy};
    this.halo = {cr:4,r:8};
    this.heading = normVec(pos,{"cx":x,"cy":y});//normalized vector vx and vy
    this.mass = mass;
    this.speed = 8;
    this.range = 500;
    this.irange = 500;
    this.color = color;
    this.delay = 25;//frame delay to allow for attack animation
    this.HIT = function (Epos,Ehalo,Ename){}
    this.hitList = {};
    this.move = function (){};
    this.kill = function (){
        this.parent.remove(this);
    };
}


Most of these properties can be used in many ways to determine the exact behaviors. For now I'll be focusing on the HIT() and move() functions.

The move() function will be called every frame and move the projectile by multiplying the heading by the speed. It also checks to verify that the range of the projectile has not been exceeded. If it has it calls kill().


this.move = function (){
    this.pos.cx += this.heading.vx * this.speed;
    this.pos.cy += this.heading.vy * this.speed;
    this.range -= this.speed;//loses power as it moves
    if (this.range <= 0) this.kill();
};

Easy. Now we have to DRAW them... For this game, the projectiles are actually a sound wave. So I used the arc() method of the canvas 2d context. By using some gradients and color stops, we can make a nice row of faded arcs. I created an "origin" for the center of the arcs 80 px behind the center. That way the arcs themselves are still drawn on the point that will be used for collisions. Then add a gradient that goes from the color to alpha 0. If you get the gradient just right, the arcs fade into nothing.


for (var p = projectiles.list.length - 1; p >= 0; p--){
    if (projectiles.list[p].delay > 0) {
        projectiles.list[p].delay--;
    } else {
        //draw the projectile
        var originx = projectiles.list[p].pos.cx - (projectiles.list[p].heading.vx * 80);
        var originy = projectiles.list[p].pos.cy - (projectiles.list[p].heading.vy * 80);
        var c = projectiles.list[p].color;
        var rangeD = projectiles.list[p].range;
        if (rangeD > 100) rangeD = 1;
        else rangeD = rangeD / 100;
        var dr = projectiles.list[p].irange - projectiles.list[p].range;
        for (n = 1; n<=8; n++){
            if (dr < (9-n) * 4 + 10) continue;//don't draw wave lines behind the character
            var wave = Math.abs((n+frameCount)%fpb-(fpb/2))*10+50;
            var w = 4*(n+4);
            var nOffset = 4*n+48;
            var offX = projectiles.list[p].heading.vx * nOffset + originx;
            var offY = projectiles.list[p].heading.vy * nOffset + originy;
            var b = Math.pow(-1,n)*20 + 80;//for now
            if (b === 100) b = wave;
            var Gradient3 = ctx.createRadialGradient(offX,offY,0,offX,offY,w);
            Gradient3.addColorStop(0  , 'hsla(' + c + ',' + wave + '%,' + b + '%,' + rangeD + ')');
            Gradient3.addColorStop(1  , 'hsla(' + c + ',' + wave + '%,' + b + '%,0)');
            ctx.beginPath();
            var nAngle = getAngle(projectiles.list[p].heading);
            ctx.arc(originx,originy,nOffset, nAngle - (Math.PI/4), nAngle + (Math.PI/4), false); 
            ctx.strokeStyle = Gradient3;
            ctx.lineWidth = 2;
            ctx.stroke();
        }
        projectiles.list[p].move();//move each projectile
    }
}

This code could be rolled into the projectile object... but I left it out while writing. Oh well. #thingsiwillfixlater #imtoolaz

The delay at the beginning is there to hold the drawing until the animation of the character has time to complete his "attack". Although I don't yet have any animations sooo it just counts down for now.

The 'framecount' and 'fbp' (frames per beat) are global variables that keep track of where in the beat the animation will be drawn. This is used for synchronization with the music. Obviously not very necessary, but I think it will look cooler if the wave pulses with the sounds.

And in case you haven't seen previous posts, the getAngle() function is below. It takes an x,y vector and turns it into radians.  Thus telling us which way to "point" the arcs.
function getAngle(p2,p1){//takes two positions as parameters, or a single vector
    if (!p1) var angle = Math.atan2(p2.vy,p2.vx);
    else var angle = Math.atan2(p2.cy-p1.cy,p2.cx-p1.cx);
    return angle;
}

Full code and a playable demo (without sound for now) coming soon. Next post will be about how the waves work in the game play mechanics and the use of color and "dissonance".

Accidents Do Happen

So after four great posts about how to avoid collisions, now it's time to talk about collision detection.

Our characters are now successfully moving from point A to point B and usually avoiding each other. Just like in real life though, when it's crowded, people bump into each other. This looks like a job for Collision Detection!

The concept is pretty simple: in my sample, each entity is described by a circle, or more practically, a center point and a radius. We merely determine if they overlap or touch. Solved.

UNLESS you also want to know the point of collision and the force of the collision. Then you need some fancy vector math. Here's a great link to explain the details. I'll break it down into the important steps though.

Step 1: Did the objects collide?

This is easy math. We take the sum of the radii of each object (since they are all treated like circles). If the distance between their centers is less than sum of the radii, the objects have collided. Since the Math.sqrt() function is somewhat costly, it's faster to skip the square root when determining the distance and use the square fo the sum of the radii.

Step 2: What was the collision point?

Some more simple math. The collision occurs at a point directly between the centers of the two circles. DUH. If the objects have an equal radius it will be exactly between them. If they are different sizes though, we just use the radii to create a ratio*. If (x1,y1) and (x2,y2) are the centers then the collision point (x,y) can be calculated thus.

 And because this is true:
...point 1 and 2 can be reversed.

*Note: Since we only check for collisions each frame, this method does not account for the fact that the true time of collision actually happened between frames. Thus, the "true" collision point is usually different. However, for the sake of simplicity, this method is more practical.

Step 3: How hard did they hit?

Now we get some fancy math. When two objects collide, they exert force on each other and "bounce" like pool balls. Newton was a smart guy. This is the code to calculate everything. It returns the new velocity for the "guy" passed to the function. You can add that to his movement vector to simulate bounce, or apply it as the new velocity if it is free-floating in space.

function findCollisions(guy){
    var velx = 0;
    var vely = 0;
    var collided = false;
    //loop through all the other objects
    for (var c in dict){
        if (guy === c) continue; //skip yourself
        if (!dict[c].collisions) continue;//skip if collisions are off
        var haloSq = dict[guy].halo.cr + dict[c].halo.cr;
        haloSq *= haloSq; //use the square to save rooting...
        var dist = getDistanceSq(dict[guy].pos,dict[c].pos);
        if (dist.ds > haloSq) continue; //they did not collide
        else if (dist.ds <= haloSq) { //they collided
            //find the collision point
            var collisionPointX = ((dict[guy].pos.cx * dict[c].halo.cr) + (dict[c].pos.cx * dict[guy].halo.cr)) / (dict[guy].halo.cr + dict[c].halo.cr);
            var collisionPointY = ((dict[guy].pos.cy * dict[c].halo.cr) + (dict[c].pos.cy * dict[guy].halo.cr)) / (dict[guy].halo.cr + dict[c].halo.cr);
            //find the TOTAL velocity of the collision
            var xVelocity = dict[c].vel.vx - dict[guy].vel.vx;
            var yVelocity = dict[c].vel.vy - dict[guy].vel.vy;
            //use the dot product to calculate the "exit" velocity
            var dotProduct = -dist.x * xVelocity + -dist.y * yVelocity;
            if (dotProduct > 0){
                collided = true;
                var collisionScale = dotProduct / dist.ds;
                var xCollision = dist.x * collisionScale;
                var yCollision = dist.y * collisionScale;
                //The Collision vector is the speed difference projected on the Dist vector,
                //thus it is the component of the speed difference needed for the collision.
                var combinedMass = dict[guy].mass + dict[c].mass;
                var collisionWeightA = 2 * dict[c].mass / combinedMass;
                //var collisionWeightB = 2 * dict[guy].mass / combinedMass;
                velx -= collisionWeightA * xCollision;//new vel for dict[guy]
                vely -= collisionWeightA * yCollision;
                //new vel for activeGuyDict.Allies[c]...not necessary since it will be calculated on another pass
                //B.xVel -= collisionWeightB * xCollision;
                //B.yVel -= collisionWeightB * yCollision;
                //draw a green dot at the collision point
                ctx.fillStyle = "green";
                ctx.fillRect(collisionPointX-2,collisionPointY-2,4,4);
            }
        }
    }
    if (collided) return {nvx:velx,nvy:vely};//return the new vector to change after all collisions have been detected and calculated
    else return null;
}

This is a fully functioning script that demonstrates my own collision avoidance/detection algorithm at work. It isn't the fastest algorithm, but it functions well enough with 32 entities on the screen. For the purposes of my own demo, there will probably be no more than 12 characters on the screen at once, so this will do fine.

Instructions:

Press any key to load the entities.
Press R to organize them into a circle.
Press B to have them randomly switch places.
Press T to split them into 3 groups that will move to a target on the opposite side of the circle.
Press G to split them into two groups. They will organize into block formations.
Press B to have them exchange sides.
Press P to organize them into two vertical lines.
Press B to have them invert the line and switch sides.

The entities turn red after a collision, until they reach their target.