MGB

Machine Gun Breaker (MGB) is all about firing a stream of Sprites quickly.

Code

// MC Library
// Machine Gun Breaker
// Jan 2019
// Purely an Alpha


window.onload = (function() {

// AQUIRE HTML DOM CANVAS REFERENCE
//     HTML has to have a HTML5 canvas element tagged as "canvas"
var c=document.getElementById("canvas");

//////////////////////////
// INITIALISE MC Engine //
//////////////////////////
// CHOOSE 1 // 

// CHOICE 1: Canvas Size fixed by HTML
MC.init(c);

// CHOICE 2: Full Window Option (Canvas will be resized to fit window)
//MC.init(c,"fullWindow");

///////////////////////////
// END OF Initialisation //
///////////////////////////
//-----------------------------------------------------------------------------
//////////////////////////
// VARIABLE DECLARATION //
//////////////////////////

// screenset up .. 900x700 canvas
MC.canvas.setSize(900,700);
MC.game.setBounds(0,1,1/9,8/9); // 100px side borders
MC.game.physicsUpdates = 10;

// container for game variables
var MGB = {
        // N.B. placeholder values, overwritten by reset() method (below)
        state: 0, // 0 = aiming, 1=firing, 2 = resolving, 3 = gameover (success) awaiting reset, 4 = gameover (failure) awaiting reset
        volleys: 5,
        o: new MC.Point(450,700), // Origin .. aka middle bottom of screen
        fp: new MC.Point(0,0), // Firing Point
        fv: new MC.Point(), // Firing Velocity
        firing: false, // are we firing?
        cooldown: 0.05,
        timer: 0,
        maxShots: 50,
        currShots: 0,
        typeFTitle: new MC.Typeface("Impact",21,"Black"),
        typeF: new MC.Typeface("Impact",21,"White"),
        typeF2: new MC.Typeface("Impact",40,"White"),
        typeF3: new MC.Typeface("Impact",40,"Red")
    };
// Sprite Bins
var shots = new MC.SpriteBin();
var targets = new MC.SpriteBin();
var GUI = new MC.GUI();
var walls = new MC.SpriteBin();
var player = new MC.SpriteBin();

// set up a boundary of top, left and right hand walls.  Invisible sprites, should not even have to update or render them.
// But they will be there for "bounce" purposes
var w1 = new MC.Sprite({type: "rect",
                       size1: 100,
                       size2: 700,
                       pos: new MC.Point(50,350),
                       fillColor: "Red",
                       edgeColor: null,
                       mobile: false});
var w2 = w1.clone();
w2.moveTo(new MC.Point(850,350));
var w3 = w1.clone();
w3.setValues({size1: 800,
              size2: 100,
              pos: new MC.Point(450,-50)});
walls.push(w1,w2,w3);

// Player "Cannon" ... composite of a barrel and a few circles .. held and rendered in player SpriteBin 
var barrel = new MC.Sprite({type: "rect",
                            size1: 100,
                            size2: 10,
                            pos: MGB.o.clone(),
                            fillColor: "Red",
                            edgeColor: null
                            });
barrel.dev.pointer = new MC.Point(55,0);
barrel.dev.update = function () {
                                    if (MC.game.mouse.y < barrel.pos.y && MGB.state == 0) {
                                        var p = new MC.Point(1,0);
                                        var t = MC.game.mouse.clone();
                                            t.minus(barrel.pos);
                                            barrel.angle = p.angleTo(t);
                                            barrel.angle = MC.maths.clamp(barrel.angle,200,340);
                                    }                                    
                                };
var back = new MC.Sprite({ type: "circ",
                            size1: 35,
                            pos: barrel.pos.clone(),
                            fillColor: "Ivory",
                            edgeColor: null
                        });
var middle = back.clone();
middle.scale = 0.85;
var front = back.clone();
front.setValues({scale: 0.8, fillColor: "SlateGray"});

// Firing Point
var fp = new MC.Sprite({type: "circ",
                       size1: 2,
                       fillColor: "White",
                       edgeColor: null,
                       pos: MGB.o.clone()
                        });
fp.dev.update = function () {
                        var off = new MC.Point(55,0);
                        off.rotate(barrel.angle);
                        fp.pos = MGB.o.clone().add(off);
};

player.push(back,barrel,middle,front,fp);



///////////
/// INITIAL RESET to start if all off
//////////

reset();

function getTarget(value) {
    var coord = new MC.Point(MC.maths.randBetween(150,750),MC.maths.randBetween(50,550));
    var t = new MC.Sprite({ type: "circ",
                             size1: 30,
                             fillColor: null,
                             edgeWidth: 1,
                             edgeColor: null,
                             pos: coord.clone()
                             });
    t.dev.lives = 30;
    t.dev.onHit = function () { t.dev.lives--;
                                setGUI();
                                if (t.dev.lives <= 0) t.kill();
                                };                               
    var c = new MC.ConBox({type: "c", width: 60, text: "TBA",pos: coord.clone(), edgeWidth: 0, colorBody: "Red" });
    
    switch (value) {
        case 1: // default
                break;
        case 2: t.setValues({size1: 20});
                c. width = 40;
                break;
        case 3: t.setValues({type: "rect", size1: 60, size2: 60});
                c.setValues({type: "r", width: 60, height: 60});
                break;
        case 4: t.setValues({type: "rect", size1: 80, size2: 40});
                c.setValues({type: "r", width: 80, height: 40});
                break;               
        default:
                break;
    }
    
                                   
targets.push(t);
GUI.push(c);
}


function reset() {
    MGB.state = 0;
    MGB.volleys = 4;
    MGB.currShots = 0;
    MGB.firing = false;
    MGB.maxShots = 50;
    shots.empty();
    targets.empty();
    GUI.empty();
    for (var i = 0; i < 10; i++) getTarget(MC.maths.randBetween(1,4));
    setGUI();
    
}

function shot() {
    var s = new MC.Sprite({ type: "circ",
                        size1: 5,
                        fillColor: "White",
                        edgeColor: null,
                        edgeBounce: false,
                        pos: fp.pos.clone(),
                        vel: fp.pos.clone().minus(MGB.o).scale(13),
                        });
    s.dev.update = function() {
            s.bounce(walls);
            if (s.pos.y > MGB.o.y - 10) {
                s.kill();
            };
    };
    s.kill(10);
   return s;
}

    MC.keys.p.onUp = function () {
        if (MC.game.paused) MC.game.paused = false;
        else {
            MC.game.paused = true;
            console.log(shots);
            console.log(targets);
            console.log(GUI);
        }
    };
   
    MC.mouse.onClickL = function () {
        if (MGB.state == 0 || MGB.state == 3 || MGB.state == 4) {
            changeState();
        }
    }

    function setGUI() {
        var t = targets.bin.length;
        var g = GUI.bin.length;
        for (var i = 0; i < t; i++) {
            for (var j = 0; j < g; j++) {
                var T = targets.bin[i];
                var G = GUI.bin[j];
                if (T.pos.equals(G.pos)) {
                        G.text = T.dev.lives;
                        if (T.dev.lives <= 0) {
                                G.visible = false;
                        }
                        G.colorBody = MC.utils.mix(new MC.Color(0,255,0,1), new MC.Color(255,0,0,1),T.dev.lives /30);
                }                
            }
        }
    }
    
    function handleShots() {
        var s = shots.bin.length;
        var t = targets.bin.length;
        for (var i = 0; i < s; i++) {
                for (var j = 0; j < t; j++) {
                        var S = shots.bin[i];
                        var T = targets.bin[j];
                    if (S instanceof MC.Sprite && T instanceof MC.Sprite && S.hit(T)) {                        
                                S.bounce(T);
                                T.dev.onHit();
                    }
                }                
        } 
    }
    
    function changeState(result) {
        switch (MGB.state) {
                // 0 = aiming, 1=firing, 2 = resolving, 3 = gameover (success) awaiting reset, 4 = gameover (failure) awaiting reset
            case 0: // was aiming ... move to firing
                MGB.firing = true;
                MGB.state = 1;
                break;
            case 1: // am firing move to resolving
                MGB.firing = false;
                MGB.volleys --;
                MGB.state = 2;
                break;
            case 2:
                if (result) { // have won 
                    MGB.state = 3;
                }
                else {
                    if (MGB.volleys > 0) {
                        MGB.state = 0;
                        MGB.currShots = 0;
                    }
                    else {
                        MGB.state = 4;
                    }
                }
                break;                
            case 3:
                reset();
                break;
            case 4:
                reset();
                break;
            default:
                break;
                        
                        
        }
    }

    function checkState() {
        if (MGB.state == 2 && shots.bin.length == 0) {// move to scoring
            if (targets.bin.length == 0) { // have Won
                changeState(true);
            }
            else {
                changeState(false);
            }
        }
    }
    
//////////////////////////
// END OF declarations  //
//////////////////////////
//-----------------------------------------------------------------------------
//////////////////////////
//      GAME LOOP       //
//////////////////////////
// first call, request subsequently made within
gameLoop(); 

    function gameLoop() {

        requestAnimationFrame(gameLoop);
        // Essential to update MC.game to ensure MC.game.deltaTime is available
        MC.game.update();

        // physicsUpdate Loop
        for (var z = 0; z < MC.game.physicsUpdates; z++) {
            if (MGB.firing && MGB.currShots != MGB.maxShots) {
                MGB.timer = MC.maths.maxOf(0, MGB.timer - (MC.game.deltaTime / MC.game.physicsUpdates));
                if (MGB.timer == 0) {
                    shots.push(shot());
                    MGB.timer = MGB.cooldown;
                    MGB.currShots++;
                    if (MGB.currShots >= MGB.maxShots) {
                        changeState();
                    }
                }
            }
            player.update();
            shots.update();
            targets.update();
            handleShots();
            checkState();
            
        }

            walls.update();        
        // Add Render / Draw Code here
        MC.draw.clearInBounds("Black");
        player.render();
        if (MGB.state == 0) {
                var end = new MC.Point(900,0);
                end.rotate(barrel.angle).add(MGB.o);
                MC.draw.line(fp.pos,end,new MC.Color(200,200,200,0.5),4);
        }
        shots.render();
        targets.render();
        GUI.render();
        MC.draw.clearOutBounds("Olive");   // Perimeter to "Olive"
        drawText();
        //MC.game.fpsLog();        
        //MC.game.mouseLog();
    }

    function drawText() {
        MC.draw.text("Machine", new MC.Point(12, 35),MGB.typeFTitle);
        MC.draw.text("Gun", new MC.Point(28, 60),MGB.typeFTitle);
        MC.draw.text("Breaker", new MC.Point(13, 85),MGB.typeFTitle);
        MC.draw.text("Volleys", new MC.Point(14, 150), MGB.typeF);
        MC.draw.text("Remaining", new MC.Point(3, 180), MGB.typeF);
        MC.draw.text(MGB.volleys, new MC.Point(36, 240), MGB.typeF2);
        var text1 = "";
        var text2 = "";
        switch (MGB.state) {
            case 0: // aiming
                text1 = "AIMING";
                text2 = "Point & Click";
                break;
            case 1:
                text1 = "FIRING";
                break;
            case 2:
                text1 = "RESOLVING";
                break;
            case 3:
                text1 = "SUCCESS!";
                text2 = "Click to Reset";
                break;
            case 4:
                text1 = "GAME OVER";
                text2 = "Click to Reset";
                break;
            default:
                break;
        }
        MC.draw.text(text1, new MC.Point(110, 690), MGB.typeF3);
        MC.draw.text(text2, new MC.Point(550, 690), MGB.typeF3);
    };

}); // EoF