10.27.2015

LMaGT Part 1 - Building a skeleton

After some reflection, I realize the dungeon crawler is going to be a much larger project that I had planned. I've come up with a lot of ideas, and it needs more time and attention than I can give it. A more pressing matter is a dire need to update my main portfolio. Click here to check it out.

I built it from scratch while I was still attending Codify Academy. At it's core, it has some cool things I'm happy to have implemented. Outside of that, it's severely lacking in actual content and direction. When I wrote the last entry, I had planned on using the Dungeon Crawler as an interactive portfolio piece. Since it's growing in scope (or at least potential), I've come up with another way to make an interactive portfolio game.

It's similar to Galaga or Space Invaders. The player controls a ship along the bottom of the screen, and shoots at stuff. In this case, the 'stuff' is the content of my portfolio. Individual letters, pictures, headlines; each separate element on the page can be destroyed. Each section can be loaded/reset by clicking the nav bar buttons. The main interface should also be optional for browser compatibility, so everything has to work outside of 'interactive' mode, and should be responsive in both 'standard' and 'interactive' modes.

If you want to follow along, here's the project folder that covers this post. It's a pretty barebones template I've cobbled together with the base elements of the game in place. Here's a quick look at the index.html:

<body>
<section id="game-area">
  <div id="enemy-box">
    <div class="enemy"></div> <div class="enemy"></div>

    <div class="enemy"></div> <div class="enemy"></div> <br/>
    <div class="enemy"></div> <div class="enemy"></div>

    <div class="enemy"></div> <div class="enemy"></div> <br/>
    <div class="enemy"></div> <div class="enemy"></div>

    <div class="enemy"></div> <div class="enemy"></div> <br/>
    <div class="enemy"></div> <div class="enemy"></div>

    <div class="enemy"></div> <div class="enemy"></div> <br/>
  </div> 

  <div id="player-box">
    <div class="player"></div>
  </div>
</section>
</body>
Not a whole lot here. Just a thing that moves and shoots, and some things to shoot at. There's not a lot to talk about in the main.css either. For now, the enemies and player are colored boxes, to be replaced later. The main.js has a lot going on though, so I'll break it into a few pieces. Going through it chronologically, it flows like this:

var fps = 30;  //Target frame-rate

$(document).ready(function() {
    window.addEventListener('keydown', handleKeyDown, true);
    window.addEventListener('keyup', handleKeyUp, true);
    setInterval(mainLoop, 1000 / fps);
});

function mainLoop() {
    calculateInput();
    detectCollision();
};
Still pretty straightforward. First, set up listeners to bind keys to movement, then use setInterval() to manage the main loop. Then inside the loop, player input gets applied before bullet collision is detected. I've got some ideas on how to handle collisions, but I'm saving that for the next entry. For now, lets take a look at the event handlers and calculateInput().

var keyLeft = false;
var keyRight = false;
var playerSpeed = 25;

function handleKeyDown(e) {
  if (e.keyCode == 37 || e.keyCode == 65) {
  keyLeft = true;
  }
  if (e.keyCode == 39 || e.keyCode == 68) {
  keyRight = true;
  }
};

function handleKeyUp(e) {
  if (e.keyCode == 37 || e.keyCode == 65) {
  keyLeft = false;
  }
  if (e.keyCode == 39 || e.keyCode == 68) {
  keyRight = false;
  }
};

function calculateInput() {
  // Move right
  if (keyRight && !keyLeft) {
  $('.player').animate({
  'left': '+=' + playerSpeed
  },{
  duration: 200,
  easing: 'easeOutQuint'
  }).dequeue();
  }
  // Move left
  if (keyLeft && !keyRight) {
  $('.player').animate({
  'left': '-=' + playerSpeed
  },{
  duration: 200,
  easing: 'easeOutQuint'
  }).dequeue();
  }
}
The handleKey functions listen for both WASD and arrow keys, but I've trimmed vertical movement. Later, I'll add a listener for firing bullets here. In calculateInput(), you can see how the player element moves by changing it's left position based on which key you press. The duration and easing give the movement a smoother feel. You can try out different timings and easings to find one that works for you.

The last call to deQueue() is important. When a key is down and the animation is called, it gets called each frame that the key is held down. At 30 frames per seconds, an average keystroke would send 4 animation calls. These animations stack (queue) until each call has completed, and the player element will keep moving long after you've stopped pressing the key. By dequeueing the animation, the 'next' frame doesn't have to wait to process, and your player will handle more like you'd expect.

In the next post, I'll get bullets and destructible enemies working, and start setting up the navbar,