Guess Who’s Been Busy

That’s right, it’s me. Capstone has been very taxing on my time, leading to a backup in blog posts.

Quite honestly my preferred method of blogging would just be to update you on everything we’ve done in a style more fitting of “Here is our game as of now, there are many changes,” but I’ve got to have a certain number of blog posts for the class. As such, I’m just gonna keep doing what I’ve been doing, but with updates for each week that we’ve done so far.

That said, week 10, wherein I:

  • Culled NPCs
  • Added a sound manager
  • Allowed vertical movement (for our ship painting, you can climb on the nets to go up)
  • Added functionality for a variety of painting interactions, using the cannon present in the ship painting and the well in the farm painting.
  • And yet more bugfixing

It was on the lighter week, and unfortunately because of how much more work needs to be done this week (presentations on Monday), I’m not going to do pictures.

It’ll be a little dry and boring, but there are more pressing matters to attend to.

So I culled NPCs, which basically means there’s an NPC system set up. For our game, it’s simplistic, we don’t have many NPCs, but if the forest painting has the potential for an NPC, he only appears in designated paintings, thus preventing every forest painting from having an NPC.

Nothing terribly exciting about the sound manager, that was just my first attempts at putting a wrapper on Unreal’s sound system to make it a bit more designer friendly and centralized. Has a play sound function, real fascinating stuff.

The vertical movement was the first iteration of allowing our player to travel up and down. It involved a lot of switches to gravity and movement before I decided on using Unreal’s character movement modes, and just setting the character to flying. Later we created a space painting that utilizes this mode.

Now the painting interaction functionality was the big one for that week, and core to the game. To properly have it so puzzles weren’t just used to travel between each other, we had to have the meta puzzle of the room, and then mini puzzles that you use to solve a larger puzzle. So the cannon interacts with all the different paintings – blowing open new passageways in the farm and snow paintings, tilting an adjacent ship painting, tipping a tree in the forest painting, etc, and the well does things like puts out the campfire in the forest painting, creates an ice block in the snow painting, and recursively triggers wells below it.

There’ll be more updates on how the week’s have gone soon, but as of now, sleep is pretty necessary to retaining a stable headspace. Until then.

The Tank Battler, Combat: Prep

As stated in the last post, our Artificial Opponents class is wrapping up with an in house tank battler.

We already completed the movement part of that (kind of). Honestly, Capstone’s been eating away at most of our times (“our” being the collective class, including myself), so the quality of my movement AI and others was significantly weaker than it would’ve normally been.

Luckily (or unluckily, depending if our Capstone game makes it through), the final presentation is next week, so we’ll have more time to work on Artificial Opponents as Capstone moves to the backburner for the end of the semester.

As for the actual tank game, and plans – well, the first step is to fix the movement and actually get it working properly. That’ll be critical.

For the combat section, I figure I’ll be casting map-wide lines to check for friendly/enemy tanks in front of me. Fire if enemy, don’t fire otherwise.

I was imagining I’d have all 4 tanks line up in a diamond-square formation and just rotate as a massive supertank, covering all four 90 degree directions, that way the time to rotate in a circle is automatically cut by a quarter. It’s a big demand, I don’t know if I’ll be able to do that, especially if two tanks at different angles demand my attention, and I need to break them out of their supertank formation, destroy their enemies, then reform and continue moving.

I haven’t yet decided if this strategy will be best for attack or defense, but that will depend on how the scoring system is determined. If it’s best to go out, destroy tanks, pick up cash and spend it for better parts, I’ll go for that loop. If sitting in a corner and killing anyone who gets near using a spider-like supertank works best, I’ll go for that.

Only time will tell really, but for now, it’s all coming up Capstone, gotta get back to that. Until next post.

The Tank Battler, Movement: Prep

The final project for this semester’s Artifical Opponents class is a custom-made tank battler, wherein you control 4 tanks all at once and attempt to take out 3 other teams of tanks on the map (for a total of 16 roaming tanks).

For the first part, we have been tasked with getting the tanks to move. This ends up being more complicated than it sounds because the tanks don’t move on a standard “I want to go from position A to position B,” where you just follow the path. Instead, the tanks move using two treads, which each have a power level that you alter.

To turn with the tank requires uneven amounts of power, but either way, that will take experimental time to basically nail down how much power is required in each tread to get it to move as I want.

The plan as stands is to use A* for pathfinding. It’s a popular, strong, and simple pathfinding algorithm to use, and because the tank battler as a whole also has things like shooting and buying equipment, I don’t want to get bogged down in just the movement system. For this first part, movement is all that is necessary.

As for determining treads, I figure I’ll create a function that takes in the degree that the tank wants to turn, and from there factor that into two workable power tread levels, for a period of time. To turn 90 degrees to the right, I’d want to power the left tread forward at full and the right tread backward at half. Or so I think.

As of now I don’t see a reason to not make turning as fast as possible. If I can mange to spin my tanks 180 degrees in a quarter of a second, I would imagine that gives me a tactical advantage than doing it over 2 seconds. But if I manage to do that, others will too, so it might determine how I create AI later, when shooting and inventory come into play.

Anyhow, next up is to actually create it. See you in the report post.

Make It Snappy

A lot of work was done this week, and it was a bit of gameplay, a bit of feedback, and we have so much more to do to fully flesh it out, but I’m feelin’ good after this week.

Let’s hit the checklist of what got done:

  • Implemented a walking character animation
  • Gave the gateway on the loose hook a swing “animation”
  • Gave the gateway falling off a loose hook a full camera transition, including screenshake
  • Added a raycast blocking wall for puzzle design
  • Implemented a top tier Programmer Art™ pause menu complete with two entire buttons (very advanced)
  • Added a transition upon activating a real world connected interactive object within a painting
  • Added bidirectional asset attachment for design ease
  • And a lot of bugfixes (which I won’t cover because they don’t exist anymore, which is good)

And now for the visual part!

Walking character animation


Gateway Swinging


Gateway Falling Transition


Raycast Blocker (The painting on your side of the gate is accessible, but painting through the gate is not)


Pause Menu


Interactive Object


And the bidirectional asset attachment is nothing fancy. It’s basically that when a gateway is assigned to a hook, the hook is assigned back to the gateway. It cuts out the time the designer has to hunt through the objects and set them all to each other, and instead only has to set one object.

There’s a lot more getting done every week, and next week will have even more. Until then.

The Critical Factor

Time. The critical factor in most everything is a deadline.

We’ve got a little under a month left to go, and we’re finding a balance between implementing gameplay bits and feedback bits. This past week was gameplay, here’s the rundown of all that I put in.

New hook type, loose. Doesn’t quite have the feedback, so no gif for this one, but what it does is that when you enter a painting on a loose hook and there is a hook underneath it, which does not have a gateway, and then fall with enough velocity, your gateway will fall down to the lower hook. A one-way downward travel system.

New frame type, wall scroll. Wall scrolls are the fun “paintings within paintings” meme that is brought up now and then. When you take a wall scroll into a painting, you have an in painting representation, and when you pop out, the painting comes with you. Fairly straight forward, but may add puzzle complexity if you need to handle multiple objects (still in debate).

Another technical new frame type (though technically the frame is really just an indicator, nor do we have the model in yet), Interactive. In an interactive painting, an object can be found that is linked directly to the real world. For example, we have a door on a pirate ship that when interacted with opens a door in the real world.

And the final bit was finally the implementation of our painting camera zooming in on the character and following them around, Mario style-ish. It stops on the left and right edges, but follows the player up and down as well, so the zoom is a little more close in than Mario. This was actually a bit I had held off for a few weeks, mainly because there were better things to do, but I’m also generally not a graphics programmer, so this area is less intuitive for me.

That said, this post is off the normal schedule, so I can update on a tiny few things planned for this week. It’s mostly feedback, because we need to clean up the transitions as well as add gameplay feedback for things like the loose hook. I also get to mess with transitions again (oh god) and create some invisible terrain that blocks the player from reaching paintings/hooks. Until next week.

Playing Gin Rummy: The Wrap Up

Like the Minesweeper post, this won’t be nearly as fun as the “This was my process” post. Instead, it’s just a postmortem on how I thought it all went.

This time I didn’t do as well as I’d hoped. It’s hard to rank the AIs, because we did a double elimination bracket system, so I didn’t get to play against everyone, but there were a few consistent factors.

My AI was roughly at the higher end of the middle of the pack. I could beat most AIs, but a few people had AIs who were consistently better. I actually lost to the same person in both rounds of my losses in very close matches that could have gone either way. In the round where I got knocked out, if I had won, I would have beaten him, it was that close.

There were some AIs that played less conservatively with their cards and would remove high cards from their hand very fast. In cases where they would get Gin, my AI might be sitting on a few dozen points. Needless to say, those AIs generally beat mine.

Compared to AIs that had a similar strategy to mine, it did generally well. A few had a similar strategy to my own, doing things like removing pairs of Kings and keeping single cards of low cost.

Alan once again was the definitive winner. His AI never lost a single match against anyone else (for clarification, a match was 40 games). I asked what he did, and he used a similar base as my own, but improved it with weights on discarding certain cards. As he fine tuned the weights, the AI got better.

I do wish I had added that myself, but time was unfortunately sparse, the capstone project consuming the majority of my time.

Either way, the next project is a custom made Tank Game, which is thoroughly complex (to code, it’s fairly simple to actually play), so that will be an interesting challenge. Because it’s custom made, right now it’s got a lot of bugs. Certainly going to be interesting with all the fixes coming in throughout. Until then.

Playing Gin Rummy: The Good Part


First off, since the last post, a new condition for the game was added: passing. Passing occurs right after the hands are dealt but before the first player makes their move, wherein both players trade a single card to each other.

Now then, much like with Minesweeper, all the AI logic used here is entirely my own, which feels more natural given that Minesweeper makes heavy use of algorithms, where Gin is more of a weighted system when determining which card you want to pick up or discard.

I won’t include a results section, as there’s no real test I can run purely against my own AI. Every time I want to play, I have to play against another classmate’s AI (or the really awful default AI), and my success can only be measured in comparison to theirs.

That said, my initial testing (and I tested against every single AI available to me) was fairly positive. I did very well against most people, with two individuals (Alan, who took first place in Minesweeper, and James, who placed first in the initial dry run (which to be fair is very preliminary, many AIs were not ready at the time)) I measured specifically against. With Alan, his AI is all over the place, and I’m not sure why. One series of games it would go from doing very well to doing very poorly, with no set pattern. James was more consistent, but in my favor, I was able to beat him 4 out of 5 times.

The Process

For this post, partly because of length, but mainly because posting code feels rather pointless (It’s our professor’s custom built engine, so while readable, copy-pasting would be useless), I’m just going to cover the step by step process I take through playing Gin.

Disclaimer: I will include parts that are not in use (but if I improved the AI further might’ve been). This AI is not fully optimized, it does not take probability into occurrence, nor does it find pairs among two separated cards (5 of spades and 7 of spades are not considered special by the AI unless a 6 of spades appears).

Notable Variables, Structs, & Functions


  • UINT myPlayerNum, keeps track of the player number (wow who could’ve guessed)
  • bool justReset, boolean for determining when the game was just reset, gets turned on once and then off in the first draw phase after an update
  • vector<Card> hasBeenSeen, a master list of all cards seen (Does update, but is not used; could be for probability)
  • vector<SetOrRun> lockedSORs, a list of all sets or runs, all cards in this list are not allowed to leave the hand
  • vector<Pair> heldPairs, a list of all pairs (both of potential runs and sets), cards in this list are only discarded if there are no “single” cards
  • vector<PCard> handPriority, a list of all cards in hand, each is given a priority number of 0, 1, or 2 (high to low priority)


  • Pair, keeps track of 2 cards, whether they’re the start of a set or run, and overloads the == operator to compare pairs
  • SetOrRun, keeps track of 3+ cards, whether they’re part of a set or run, and overloads the == operator to compare SORs
  • PCard, a struct that holds a card and a priority number


  • bool completesOrAddsToSetOrRun(Card c), determines whether a given card completes or adds to a pair or a SOR, true if it does
  • void cullDiscardFromPairs(Card c), removes all pairs that contain the discarded card from heldPairs
  • Card getCardToDiscard(), browses the hand and finds the highest priority card (a 2 if possible) with the highest value
  • void setHandPriority(Hand h), adds all cards in hand to handPriority with an associated priority number, clears the previous handPriority list when called

Step by Step

  1. Upon resetting the game
    1. Clear all lists (hasBeenSeen, lockedSORs, heldPairs, handPriority)
    2. Add the discard to hasBeenSeen
    3. Set justReset to true
  2. Determine passing step
    1. updateOnReset, which:
      1. Sets the player number
      2. Adds your hand to hasBeenSeen
      3. Finds any sets or runs in hand and adds them to lockedSORs
      4. Finds any pairs and adds them to heldPairs (includes pairs that are apart of SORs)
      5. Removes any pairs that are in SORs (so as to not trick your own system)
      6. Set hand priority
    2. Get the card to discard
    3. Cull the discard card from pairs
    4. Return the chosen card
  3. When it comes to your turn, determine whether you’ll draw from the deck or discard
    1. Update, which does everything that updateOnReset does except for setting the player number. However, it also checks for duplicates on each list, and does not add any cards to hasBeenSeen, pairs to heldPairs, or SORs to lockedSORs if they already exist within the list. It also assures that if pickedUpInitialDiscard is true, then do not access the top of the discard (because there is none)
    2. If completesOrAddsToSetOrRun is true, take the discard. Otherwise take the deck
    3. Flip a few reset variables (will only happen once)
      1. If justReset is true and you chose the discard, flip pickedUpInitialDiscard to true. This was a fix for this particular system, but it avoids the issue in the next update wherein you check the top card of the discard, and if its empty (because you just picked it up), it won’t throw an error
      2. If justReset is false and pickedUpInitialDiscard is true, flip pickedUpInitialDiscard back to false
      3. If justReset is true, flip it to false
    4. Draw your card
  4. Now you must discard
    1. Update to redo calculations for your newly drawn card
    2. Get the card to discard
    3. Remove that card from your hand and score your hand. If you are under the knock threshold, take the knock (set to true), doesn’t matter what value (our default value is 10)
    4. Cull the discard from pairs
    5. Discard your card
  5. Repeat steps 3 and 4 until the game ends

It’s a lot more compact that I expected to write, but there’s a lot of backend functionality that doesn’t warrant a spot on the list.

Functions that determine sets and runs from your hand, pairs, checks for duplicates among lists, checks the best form of scoring (whether it be from taking the 5 of hearts, 5 of diamonds and 5 of clubs, or the 5 of clubs, 6 of clubs, and 7 of clubs as your set/run), breaks apart a list of cards returned as SORs into the actual SOR struct, a lot goes on to actually run the base update function, which is where most of the information cataloging is done.

The deterministic functions, which get the card to discard or checks if the card completes a set or run end up using those lists of information to check whether they want a given card or not.

Final Thoughts

I predicted it last time, and I’ll be bold and predict it again: I think my AI will do well. I’m quietly hoping that it will place first this time, but just as Alan dark horsed his way in last time, there’s always that possibility that someone will have a strong AI that gives challenge.

I also don’t have a unique algorithm that’s leading the charge, just a series of logical choices that I as a player would make (albeit as a player I might use more nuance in some decisions, but god damn if nuance isn’t the trickiest thing to program), so I feel less confident that I will do well this time (but still fairly confident).

I guess we’ll just have to see how it all shakes down tomorrow or Friday, whenever the actual competition is. Till the next post, thanks for reading.

When The Masses Ask…

The big area focused on this week was player feedback, as we got a lot of QA responses that wanted to know more information about the world and their physical relation to it, especially when travelling through paintings.

The big two areas that we improved feedback through was via a render texture mesh that we added to the gateways in the real world (this is of the forest landscape):


And by adding a camera transition in two parts: moving in/out of a painting, and between paintings:



The other bit of player feedback attempted to expand on was the narrative. Besides just fleshing it out in the week prior, we implemented a very basic NPC (can be seen as the red block in the gifs above – very creative I know), that when you walk past says a bit of dialogue to you. Nothing fancy for now, but paves the way for easy implementation later.

Finally, the two bits of functionality we threw in for this week were a new frame type, the latched painting, which is a frame that can be dived into but not moved from it’s location, and having interactive objects within paintings.

This is our latched painting:


The interactive objects, first off, replace the collider that it’s on the side of. For example, our snow painting has an igloo on the left side, which counts as our interactive object that disables the left collider travel option (you can still collide, you just won’t travel between paintings), and you will only travel upon hitting E (which later will be accompanied by an animation).


This next week’s focus is on improving gameplay, mainly in the painting world, but also adding new hook and frame types to add puzzle variety, so tune in then.

Infrastructure Is Key

We’ve taken our Painting game, which still does not have an official name, and are working toward fleshing it out considerable. Giving it pizzazz where we can, and working toward that final vertical slice for the end of the semester.

My main area of focus, being the first week of solely working on just this one game, was on improving the infrastructure of the areas I more quickly set up, and cleaning up our repository so it doesn’t take four centuries to download.

Repository cleanup went well, I’m somewhat anal in my organizational formatting for the folders that I use and access, so I like to have things easy to find and not all over the place. Helps me at the very least, I like to imagine it helps others too.

Matt (Designer) added a third, more complex puzzle, and a background piano track that he composed himself. It’s a little simple, but it’s only the start, I expect great things.

We got two bits of player feedback in. First, when you are holding a painting and are near enough to place it on a hook, the hooks glow. Considering our hook model is somewhat visually diminished, I found it pretty helpful when I was testing the levels. It does help that Tucker (Artist) put a nice background to accentuate the “You can place a painting here!”


The second bit is the frame’s give you a direct visual indication of where they’re connected to. Easier to show then tell so…


And that updates on the fly as you go.

Final bits worth noting are a variety of bugfixes and infrastructure improvements. Three of note:

  • Each painting type now has far easier designations of entrances and exits on all four sides.
  • Paintings would occasionally stay highlighted when they shouldn’t and only one object could be highlighted at a time, both of those are now fixed.
  • The distance at which you can pick up/put down a painting is differentiated from the distance at which you can dive into a painting. Good for some puzzles. Matt has a puzzle with a gate that enforces that limit. In the future we’ll have different painting and hook types so we don’t need direct physical barriers.

That’s this week. We’ve got a lot planned for next week, so check in then.

The Chopping Block

The pain of working with full 3D physics is over. Snails have defeated me.

But honestly I’m not sad at all. While it was a challenge, it taught me a lot about Unreal as an engine, both in blueprints and with their C++ code base. And I even went to a professor who was super helpful in terms of teaching me about quaternions and how they work (much thanks Dan).

On the positive note, we have decided to move forward with the Painting game (name still pending), our Gothic themed puzzler!

To show off some highlights, here is our starting room:


And when you near the paintings, they glow to signify that you can carry them!


So far, our first two painting types, forest and snow:


The little copper-ish capsule (placeholder) is your character, who moves around the paintings and bumps into walls to switch between paintings.

And finally I’ll show off the (technically second) puzzle, where you have to grab the two paintings on the walls and move them to the hooks (which are the stone squares on the wall right now). That allows you to dive into the bottom painting, maneuver your way into the upper painting (by using the tree and cloud in the foreground of the forest painting) and then go right to appear in the painting on the balcony, which you can then pop out of, and you’ll have solved it!


Overall, super happy with the progress made, it’s a fairly solid initial prototype. We’ll be looking to challenge this week, so ideally that will succeed and put us into deep dive where we can take this game and push forward with it even farther (though we’ll end up doing that anyways, but professors’ blessings are always nice).

Final bit, if you want to try out the prototype, it can be found here!

More to come in another seven days!