Posts By Justin Osterholt

Getting More Familiar with Docker

I’ve been spending this week getting more familiar with Docker. I’ve learned how to build new images, spin up a collection of related containers with Docker Compose, and push an image to AWS.

I’m pretty excited about how this will help my team, but I’m also nervous about the unknowns we’ll encounter. My goal is to free up time, not take up more.

It’s important to know what Docker is and isn’t. To be honest, I’m still a little fuzzy. I wrote about this in my last post.

Docker utilizes virtualization technology to run processes in isolated environments called Containers. It has some similarities to virtual machine technology, such as VMWare and VirtualBox.

Docker Containers do not hold an OS, but they do have libraries and binaries from other OSes.

After working with Docker a little, I’m now much familiar with commands to setup a container and access the container (docker exec -it is my friend). I’ve also gotten more familiar with docker-compose (docker-compose up/down are pretty cool).

The documentation for Drupal on Docker provides info on both setting up Drupal and MySQl.

I’ve been able to spin up a Redis and MySQL server with Docker, it has simplified the setup and given my team a consistent toolset.

Regularly Scheduled Maintenance

For about the past year I’ve been putting my time towards planning and managing projects and less time with implementation.

I was stubborn in accepting I didn’t have enough time to both manage and code. I learned the hard way.

I tried to code out a complex solution that ended up taking a long time to finish, because I kept getting pulled away. After that, I focused more on coaching. Guiding my developers to make good decisions has become a more effective use of our time.

One challenge with this approach is my coding skills are becoming a little rusty. My memory of higher level design is fine, but my familiarity with the code base and specific implementation has started to become fuzzy.

Another challenge is keeping up to speed on new features that come out for languages and frameworks. Last year I had an instance that caused a little conflict when I wasn’t familiar with with some new React features that had been announced the year before.

There is a question I’m hoping to get an answer for this year; is it possible to be a technical lead and a manager?

I’ve heard of positions that are both, but my personal experience has shown me it’s difficult and probably best there’s a separation of the two.

Regardless of if I hold on to those responsibilities or not, I want to keep my skills up to date. And that requires some routine maintenance.

I think it’s best to focus on one area at a time, which has me a little torn. Do I put that attention on work or hobby? That’s a topic to delve into more in another post. For now, I’m going to side with work and explore Drupal more.

I was tempted to say Drupal and React, but I need to limit myself to reasonable goals.

Putting in any time to perform any maintenance is an improvement over the past two months.

My target is to get Drupal setup in an environment to test out the layout builder and see how their database schema is structured.

Wish me luck!

An Uncertain Path

I’ve been working towards becoming a Software Engineer Manager for several years now. 2019 was a crucial year for my path to management that held as much doubt as it did promise.

At the beginning of the year I was working with my director/manager to officially request a promotion. I had been shadowing and taking on management responsibilities over time.

The more managerial tasks I took on, the less coding I was doing. That was expected and I was fine with that. I was still able to create proofs of concept and stay ahead of my developers.

However I hit a roadblock along the way that postponed my promotion. There were some things I still needed to work on to make others comfortable with me managing. It was a strange time in my career, I felt like I was losing touch with my software engineer skills and I wasn’t a manager either.

To be honest, it was a bit scary because I thought I was existing between roles and facing the reality my path may dead-end.

One fear that kept creeping up in my mind was becoming rusty with programming. If things didn’t pan out with management, would I be in trouble from rusty programming skills?

I got my answer towards the later end of the year after looking into what responsibilities a lead hold in other companies. For some, it didn’t differ much from what I was doing. The responsibilities for management and a lead could overlap quite a bit.

I no longer felt as lost, but I had also gained a lesson; roles aren’t cookie cutter. From company to company, they mean different things. And over time they may be redefined (though there are some foundational attributes that stay the same).

Fast forwarding a bit, as of last week I finally got my promotion. It involved quite a bit of personal growth that I didn’t touch on here.

What I’ve been focusing on here is feeling in between roles and discovering it isn’t abnormal.

However others may have a more well defined sense of roles. Mileage may very.

I still have a fear of letting my skills become rusty. This last weekend it became apparent I need to work on some side projects again to sharpen my skills.

I’m feeling really good about my daily responsibilities though and am looking forward to helping my developers go and working through challenges.

More on that later.

A* Pathfinding In Game

I wrote a post on implementing a simple A* Pathfinding algorithm a couple months ago. When I went to add it to my game I ran into some interesting differences I wanted to write an update on.

Here is the algorithm working on my game server. Both player and NPC are red blocks. When the player is within viewable range of the NPC, the NPC will start chasing it.

The pathfinding algorithm allows the NPC to maneuver around blocked tiles.

Coordinate to Tile Mapping

One thing I discovered while incorporating it into my game was my simple example had a 1:1 coordinates to tile ratio. Coordinates 0,0 was the first tile, and 0,1 was the second tile. When tiles were 16×16 pixels, the coordinate to index mapping broke.

To address this, I needed to pass  map width and map height in tiles, as well as the tile size so it was known when a new row started and the bounds of the map.

I did this by creating a map struct that contained the width, height, size, and pointer to the tile vector.

struct GameMap {
	GameMap() {}
	GameMap(int _map_width, int _map_height, int _tile_size, std::vector<unsigned int>* _tiles) : map_width(_map_width), map_height(_map_height), tile_size(_tile_size), tiles(_tiles) {}
	int map_width = 0;
	int map_height = 0;
	int tile_size = 0;
	std::vector<unsigned int>* tiles;
};

Metroid: Samus Returns

Metroid II is one of the most memorable titles for me on the Gameboy. The game play, aesthetic, and soundtrack  are really good and create an immersive experience.

I remember being sucked into the alien world. The sounds and environment were strange and mysterious.

One memory that sticks with me is after defeating a metroid, sometimes the soundtrack/sound effects would change, giving the impression that my actions had somehow changed something, and adding to the suspense of what would happen next.

In all, this was a game that fully immersed me, encouraging me to explore and take my time, instead of trying to just get through each level. Investing the effort to solve puzzles was well worth it and gave a bit of an edge against the next baddie.

In 2017 Metroid: Samus Returns was released. This is a remake of Metroid II that sticks to the core of what made the classic, while bringing it up to modern times with some quality of life improvements and additional changes. It’s different, yet unmistakably Samus Returns.

October Development Progress

This is the first of my weekly reviews. I’m starting this to help keep track of what I’m doing and and to set forward goals.

The past two weeks have been a mix of new and old projects, including business-oriented project planning web applications, a World of Warcraft data sync, and two game development projects.

Asana Features

I use Asana to manage my teams tasks. Asana is very simple and flexible, but is missing some features we need to keep track of our sprints and better organize our tasks and Kanban board.

Sprint Reporting

One of these missing features is a burndown chart based off of effort estimation. I’ve been building out our own burndown chart in an Electron app using Google Charts to display the statistics and feeding in the task data from Asana using their API. At this time I’ve got the chart but also a break out of the effort we’ve committed and the effort we’ve knocked out.

This has already proven to be really helpful, as we now have an easy way to track our progress and see the sum of effort completed at the end of the week.

Asana Bot

Asana supports custom fields, but doesn’t allow us to make them required. Requiring the effort estimation for a new task would be ideal. In addition there are a few other events where I would want additional info provided, such as when a task is labeled as blocked, a due date is passed, or a new task is added to the sprint.

To solve these problems, I’m building out a Slack chat bot using the Botkit framework. So far I’ve been learning the ropes of what the chat bot can do and building out the groundwork.

October Gaming Progress

Here is a quick look at the games I’ve been playing recently. I’ll try to post some updates on progress now and then.

This time around, I finished Metal Gear Solid (1998), some World of Warcraft, Destiny 2, and Diablo 3.

Metal Gear Solid (1998)

I finally completed Metal Gear Solid after many deaths from the Metal Gear mech and the fist fight with Liquid Snake.

MGS is a game I watched being played and beaten. Though it’s been so long I could only remember pieces of it. Needing to  transform the card key between rooms was one of those pieces, though I thought it was in a different game in the series.

Finishing it myself was gratifying. There were a lot of frustrating and tiring moments. I have the Metal Gear Solid HD Collect (MGS 2, 3, Peace Walker) to finish at some point.

World of Warcraft

I jumped on WoW and ran an instance of “The Motherlode!”, which was interesting experience with other players. I was playing with a new tank (but not new to the instance) and unfortunately I kept aggroing mobs when I chased bubbles from the Azerite armor talent Secrets of the Deep. I may need to switch that out. The dungeon map for “The Motherlode!” is pretty open with branching pathways. If you meander or lag behind, it’s easy to accidentally pull enemies. So far this is my least preferred Dungeon, strangely, this makes me want to play it more so that I will learn how to do it right. My favorite Dungeon so far is Waycrest Manor.

A Simple A* Pathfinding Algorithm

Pathfinding is a fundamental tool commonly used to move characters around a map intelligently. Here I will be going over the A* algorithm written in C++.

It’s important to visualize how the pathfinding algorithms search for the most efficient path. Here is a neat demo using a JavaScript library called Pathfinding.js. By playing with Pathfinder.js, you should notice that the algorithm first tries to go straight for the end point and only when it hits a blocked node will it look for nodes that follow a less direct path.

The Algorithm

In a nutshell, the A* algorithm uses a graph of nodes that have a weight associated to them used to weigh paths from the start node to the end node.

What weight represents is arbitrary, since A* can be applied to different scenarios. For navigating through a map of squares for example, this value could be based on distance and steps taken. The algorithm processes neighboring nodes, adding all neighbors to an “open list” and then moving on to the lowest cost node in that list.

Given the open list begins with the start node (opposed to be empty), the main loop of the algorithm looks like this:

  1. Get next node from open list (now known as current node)
  2. Skip node if in closed list or out of bounds
  3. Add current node to closed list
  4. Remove current node from open list
  5. Process neighboring nodes (North, West, South, East)
    1. Set current node as parent of neighbor if weight is less

In all, the algorithm uses three lists:

  • Open List:  Keeps track of which nodes to search next and is ordered by weight
  • Closed List: Al nodes that have already been searched
  • Path: Linked list that connects the end node to the start node

To clarify on the path, there are actually multiple paths that exist because less efficient paths may be found before the most efficient path. The end node will have the final path, and that is all we care about.

Implementation

Next we’ll go over the structures and functions involved with this algorithm. One core structure is the node.

Node Structure

As mentioned before, this is implemented in C++ and the graph is comprised of nodes.

Here is the Node structure with only its members:

struct Node {
    int x;
    int y;
    int index = 0;
    int distance;
    bool blocked = 0;
    int weight = 0;
    Node *parent = NULL;
};

I use indices to keep track of nodes. This includes determining which node is the start and end, as well as which nodes have already been processed (closed list) and which nodes should be processed next (open list).

Note: The index  struct member is there for convenience, so a coordinate to index lookup doesn’t need to be run every time.

The path list mentioned before is a linked list created through the parent  struct member, which points to another node.

Grid and List Structures

Nodes are stored as pointers in a vector. The open list is implemented as a multiset with the comparison function, NodeComp, so sorting is automatically done. Lastly, the closed list is implemented as a vector of ints that stores the indexes.

typedef std::multiset<Node*, NodeComp> NodeList; // So we don't need to type out the full definition everywhere

NodeList open_list; // Node pointers to process
std::vector<int> closed_list; // Node indices already processed
std::vector<Node*> grid; // All nodes

Battle for Azeroth Pre-Patch

var whTooltips = {colorLinks: true, iconizeLinks: true, renameLinks: true};
Being someone who wants to make games for a living, I find it disappointing how much I miss or don’t complete in the games I play. Time seems to slip away and I ask myself why I didn’t do more. One of my big goals this year and prior was to rediscover what I’m passionate about, what motivates me. Fantasy and games are two things I love.

July has been a month of reflection and trying to get back on track. Instead of talking about what and why hasn’t, I’m going to focus on what has happened and I want to happen.

Pre-patch Preparation

This month I’ve been preparing for the upcoming World of Warcraft expansion, Battle for Azeroth. This includes taking care of some things so I don’t need to backtrack (ex. flying) and achieving some things before they go away for good (ex. artifact appearance).

First I want to reflect on my thoughts and feelings on flying being gated and in-game items (gear, appearances) going away after the expansion ends. I’ll bring Diablo III into this as well, as it has gear and other goodies it rewards players when they finish season achievements.

Flying over Suramar after pathfinder achievements completed

Flying

Even though it was way late into the expansion, I was able to gain my flying in Legion, something I didn’t do in Warlords of Draenor (previous expansion) . So this was a special feat for me. It was challenging given my availability, I am balancing games with family and side-programming. This means I have to be selective about what I invest my time in and it’s possible I won’t get what I want. It also means I need to be smarter about how I do things, something I’m still learning.

Not having flying during the leveling experience definitely helps with immersion. Flying makes it easier to escape and access areas more easily, but waters down or nullifies the experience of exploring and adventuring because the danger is no longer there and discovery isn’t as much of a challenge anymore. In this way, I appreciate what current and past expansions have done when they lock down flying. It makes the danger and achievements feel that more real.

With that said, achieving flying in Legion was a challenge and I had to step away from it at some point. I found myself stuck in progressing through the main storyline because of a reputation gate and my timing was off for dungeons and raids. I tried chipping away at the rep, but at the time I still had at least three factions to gain reputation with and it felt cumbersome.

When I came back to the achievement, I had a more focused effort by only doing world quests for one faction at a time and using WoWHead to get passed the quest blocker I was running into. I also finally knuckled down and completed some quests in raids.

I’m hoping in Battle for Azeroth I will have an easier time keeping up with the rep grind, I think that’s the biggest factor that made me step away. As much of a pain it was, being challenged to get flying made the expansion better. I experienced the full content when I would have skipped out on Suramar and missed the conclusion of that questline.

Global Game Jam 2018

Global Game Jam 2018 took place at the end of January. It was hosted locally here in Sacramento at Square One Clubs. I participated as much as I could, but unfortunately I had some family obligations that prevented me from making it down to the site.

For my game, I created a first person puzzler in a 3D world. I used it as an opportunity to get more familiar with Blender and Unreal Engine. With this being a learning experience, I didn’t get as far as I would with tech I was already familiar with. Overall, it felt like a success. I am now much more comfortable making shapes and applying textures in Blender. I also learned what is lost while exporting a blender project into Unreal, such as shaders that are closely tied to the rendering engine.

Alright, so lets take a peek and go over some stuff!

My game takes place in a testing grounds with various platforms and standing orbs. In this first iteration, it takes place in space, but after building out the platforms that idea didn’t seem to pan out so well, for reasons I’ll go into shortly. The skybox texture was created using a premade texture from SpaceScape, a free tool for creating space skyboxes.

Unreal is a very powerful engine with some very useful tools in prototyping a scene. You can create shapes in the scene on the fly. Unfortunately (at least as far as I know) those custom shapes, known as brushes, are their own object type and I couldn’t find an easy way to convert them into components for reuse. I imagine it’s possible, the answer just wasn’t easily at hand. I created the octagon platforms and the orb with stand using brushes.