Today saw the advent of an actual player character! This includes a rudimentary system for animating characters, and a nice, smooth way of managing multiple characters. I also did some refactoring to separate the concept of controls from the game world.

Continuing the trend of not putting these in any specific order, let’s start with the easy stuff: Inputs.

Inputs

This one threw me for a loop for a little while, I won’t lie. I actually got it sorted out about five minutes ago, as I sat down to write this blog post. I attempted to solve the problem by adding values to a velocity. Now, this would work great if I were building a physics-based game; adding forces to velocities is literally the basis for all phsyica engines. But I started without thinking that simple fact through, and just trying to add and subtract up, down, left and right vectors from a normalized velocity.

Yeah, it was dumb, and a complete waste of time.

What ended up working was, you know, establish my velocity from the result of two axes of movement:

private registerControls(){
  document.addEventListener('keydown', (e) => {
    // set the direction to 1
    this.player.playerInput(this.calcMoveVector());
  });

  document.addEventListener('keyup', (e) => {
    // set the direction to 0
    this.player.playerInput(this.calcMoveVector())
  });
  }

private calcMoveVector(): Vector2{
  const horizontalMovement = this.right + -this.left;
  const verticalMovement = this.down + -this.up;

  const newVec = new Vector2(horizontalMovement, verticalMovement);
  newVec.normalize();
  return newVec;
}

and then setting my velocity, rather than adding to it:

playerInput(inputs: Vector2){
  this.velocity = inputs;
  this.velocity.scale(this.speed);
}

I’m waffling on whether the input controller should handle normalization, or the player class. Meh.

After fixing a minor bug in my vector class (okay, I forgot to check for zero), I was off to the races!

movement!

Animation

I am not a good animator. I started drawing out a test goblin on my phone (Thanks, S Pen!), and it, er, wasn’t great:

test gobbo

Then I gave up and went to OpenGameArt and pulled down this nice little spritesheet for my goblin. It turns out the animation frames aren’t perfect in this, but I think that’s okay for now. Now, I needed a way to handle animations!

Remember when I said I wasn’t going to bother with spritesheet animations? Because, well, they’re “complicated” and “difficult” or whatever? Well, they aren’t complicated, nor are they difficult, when you comparte them to having to manuially draw out frames correctly. So, I built a SpriteSheet class that lets me define how big spritesheets are, how many columns and rows they have, all that jazz. This involved reconfiguring a few things in my (brand new) Player and Character classes. Essentially, I let the Character manage what state they’re in, and that tells the CanvasManager where to look in their spritesheet.

I think it’s a rather elegant way of going about things in something this small. It separates the presentation layer from the domain layer pretty well. The only thing presentation-wise that remains with the player is the animation frame number. I think I need t pull that out and stick it in the spritesheet class, or maybe some kind of AnimationRow class like I did for my tests. I’ll need to define these things in some kind of data file somewhere. Maybe a task for our BlobResource Resourcetype?


All in all, I did a pretty good job of staying on track today. I didn’t do too many crazy infrastructural things, and I now have working animations and input.

Up Next

Next, I want to tackle the concept of a “level”. I know that my game will have three levels, so I need a good way to define them so that they’re manageable by the GameController. The levels should have some sort of background image (which I’m currenlty hacking in directly with the GameController). Along with the levels, I’ll probably have to come up with a way to store, load, and interact with enemies, at least to get them placed in the world.

I’ll also see if I can try to get “collisions” in the game, which may or may not mean applying my QuadTree class to the game. Using this would actually make things easier to separate “screen space” from “world space”, a separation that is non-existant as of right now. Given I only intend to have the world scroll left and right, as opposed to in all directions, this should be pretty straightforward.

EDIT: Oh, yeah! Today marks the first time you can actually playtest the game over on GitLab! Go, uh, give it a try?