I changed my steering implementation to not always snap the sprite's orientation to the velocity vector. This was causing issues where slight bumps (asteroids, lasers) were making the agents freak out. Instead, now the sprite is on a separate game object that can turn independently from the 'engine', and always tries to face the player. It's a little unnatural to see a rigid vessel like a spaceship having decoupled movement and 'vision', but I rationalize it as the invaders have developed advanced thrust-vectoring engines that let them essentially hover and turn on a time.
Oh, I also changed the orientation to landscape, which gives me quite a lot more screen real estate, which was sorely needed.
Added some more steering behaviors. The first one was a "path follow" which actually isn't so much a steering behavior, as a planner for the Seek behavior.
Next was "Cohesion" which is the opposite of Separation: it induces entities to stay together. This is added to the 3 red dudes in the following video. Notice how they 'try' to stay together, while the other main groups spread out.
Started working on some basic steering behaviors for enemy AI:
I kinda already started this with the missile (seeking and obstacle avoidance), but they were totally coupled to the missile class. Tonight, I pulled them out into a generic architecture. In addition to updating Seek and Avoid, I added Separation, which keeps enemies separated.
Unfortunately, the separation kinda overrides the avoidance, so they are quite prone to colliding with the asteroids. This is a known issue and limitation of steering behaviors. Usually it is solved with weights and/or priorities, but it always ends up requiring tedious balancing of parameters to get it to 'feel' right. I'll have to cross that bridge eventually.
First things first: Ever since I added the post-processing effects, my GIFs are wayy to big (10-15MBs) for sharing. Even cutting the FPS down to 10 doesn't help much. So I'm going with Streamable videos. I'm curious what other people think of this, or what their preferred formats are.
Moving to the actual work I accomplished today:
Added a nifty shield-hit effect:
Added some missiles!:
Didn't post for the last couple days, but I actually have been busy! I added some post processing effects that make the game look ... better? I hope. The lens distortion is probably over-done, but I think it fits well with the circular nature of the game.
I also added the basics of a combat system: shields block normal blasters, but ion-type weapons defeat shields:
After spending virtually every waking moment from Feb through the end of April on my (last) class for my Masters degree, I'm finally back to game development.
Actually, there was a little thing called Ludum Dare 41 in there too. Check out my game: https://ldjam.com/events/ludum-dare/41/flatformer
But now, I'm finally back to my own games. I'm going to put Space Roguelike in Space on hold for a bit while I actually finish a game. Why? Because I realized that I had bitten off a bit more than I could chew. I still think that I can technically create all the systems and components I need, but I don't know if I have the skills or inclination to make a compelling and balanced roguelike.
So without further adieu, I'm starting a new (but actually old) game!
Yea, okay, I worked on this exact concept about a year ago, but it was really hacked together, and I never really got out of (or even into) the prototype state. I went back to the codebase, and realized that (for a number of reasons) it's unusable, so I'm starting fresh. My goal is to release this game by 'the end of the summer', whatever that means. Wish me luck!
Spent a very small amount of time determining the actual 'leaf' nodes in the room graph. These will be useful for determining start and end positions on a map, as well as placing more difficult rooms with better loot because they're off the beaten path.
To implement, I actually had to make a whole new data structure. Before, I had a collection of Rooms and a separate collection of Edges. Now, I additionally have a collection of RoomNodes that have references to their neighbors (kind of replaces edges). A leaf node is any RoomNode that has exactly 1 neighbor.
I am not doing anything with this knowledge yet, but here I added some square gizmos that identify leaf nodes in the scene view:
Not a very productive day.
I managed to clean up some stuff I broke while making the A* hallways. To make those work, I had to change the definition of what was Passable in the grid from Floors, to empty space. Next, i changed the definition of Neighbors to only be the 4 cardinal directions since I don't really want diagonal corridors (they look weird).
All of this epically broke the Player's ability to actually move, so I did some refactoring to make those parts configurable, and now everything is working.
Better than nothing!
I added the ability to connect rooms that aren't vertically or horizontally aligned.
My initial thought was to make crude 'L' shaped hallways, but I realized that they would almost always intersect some other room/hallway, and I didn't want that.
My second thought was to use pathfinding to actually generate the hallway, and I got it about 99% working. Unfortunately, I'm not sold on how the results actually look.
Here are some pics (note: new A* hallways are in brown for illustrative purposes)
This third one exhibits the issue that keeps this only a 99% solution. The 2 rooms with brown doorways, but no connected path, are supposed to be connected, but no path can be found because of the 'courtyard' formed south of the left room.
I'm already picking where to start the hallways by choosing a spot on the wall of each room that has an open-air tile next to it, but that isn't enough.
I think my 2 easiest options are:
Finally, and I almost forgot, I don't really like the aesthetic of the winding hallways anyway. They'd fit great in a dungeon setting, but not so much in a space station. Might have to go back to the drawing board...
Added some doors between rooms. Okay, not actual doors that can be opened and closed, but I carved open hallways between rooms.
I haven't covered the case that 2 rooms are neither vertically or horizontally aligned. So for now, they are inaccessible, so that's next.
Been stumped by my overly-complicated combat system lately, so I decided to take a break and start some proc-gen.
This is just a really simple algorithm that randomly places some rectangles with rigidbodies, lets the physics engine separate them, and then rasterizes the result to the tile grid. It's a start!
Was on a ski trip with my in-laws from Thursday till tonight. However, I managed to get some gamedev in on the plane ride back.
Nothing worth making a GIF of, but I made it so normal attacks will NOT trigger the defender's damage reaction if they miss. This was working for the projectile a couple updates ago, but I made it more generic for any attack,.
I also added logic so the grappling hook will trigger the OnArrival behavior of the defender when it performs the final 'kick out'. This means, if you grapple an enemy right on top of a trap, it will actually take damage.
Not a lot of motivation today. Watched the Spartans hang on to beat a shitty Iowa team by 3. Not very inspiring.
However, I managed to add a little feature. Previously, it was possible to grappling-hook anything; including traps, which I want to limit. Now, there is a flag in the base Entity class, 'moveable', which is considered when trying to grapple. Of course, the Trap wasn't actually inheriting from Entity, I had to change that.
No GIF because I can't show something not working. Also, I'm lazy. Goodnight
Updated the grappling hook to calculate the nearest non-blocked tile and 'kick' (that's what I picture in my head at least. No actual animation) the defender to that position.
It's lacking the "OnArrival" behavior when the defender reaches its final destination. This would trigger the traps attack, for example.
Started some very basic work on the grappling hook today:
The obvious flaw right now is that it pulls the enemy onto the attackers tile. This technically is allowed in my combat system, but I don't want to encourage it. In fact, I may make it impossible for 2 entities to occupy the same tile, with the exception of traps.
To fix this part of the hook, I'll have to deduce the proper nearest point to the attacker to make the destination point for the victim. That shouldn't be too hard, but I'm honestly not sure what it should look like. If the victim isn't going to get pulled to center of the attacker, where should the grappling hook start? Should it have 3 points (attacker's position, destination tile, victim's position)? Or should I just fudge it somehow?
I was absolutely not feeling like doing gamdev after work and class tonight. I actually played video games (Rocket League) for 2 hours instead of doing gamedev, which is rare for me recently.
By 10pm I finally got the motivation to do some gamedev. I wanted to add a 'grappling hook' ability that will pull an entity right in front of the attacker. This will be a utility move for melee classes for closing the distance to ranged enemies. However, when I sat down to implement it, I realized it should be loosely based on my 'push' ability which I haven't kept up to day since the AbilityVisualization and ability UI system reworks. I spent about 30m updating it to a barely functional level (didn't actually implement a visualization, but the ability still 'waits' for all the enemies to move before completing). And then I lost motivation, and am going to bed. 30m is better than 0m!
Added something I've been meaning to get to: missing! Now attacks actually have the concept of not always hitting! For now, its a straight 50/50 RNG roll, but eventually it will be configurable per the ability, and might be modified by things like Entity accuracy, blind state, or target's evasiveness.
Implementing it required giving all AbilityVisualizations the concept of 'missing' as well. The only one I've gotten around to implementing is the ProjectileVisualization. Now, it actually goes past the intended target if it misses! It doesn't do anything fancy like detecting walls, so it looks kinda silly, but that can be refined later.
Once again, my group project has been sucking my mojo away from gamedev, but I managed to be decently productive for ~2hrs of time.
The Player and the Blob were duplicating a lot of code for things like: monitoring when an ability finished, updating passive traits every turn, updating their combat component every turn. I refactored that into a base class, and now they're only different in logical ways.
Generalized the StunTrait that gets applied by certain attacks to be any PassiveTrait via another ScriptableObject hierarchy. Technically, I could make an attack that gives the enemy the passive ActionRegen trait upon hitting, neat!
Here is a GIF of the Grenade ability imparting a 3 turn 'blind' state. Blind will eventually have some effect on combat (lower accuracy?) but for now it doesn't actually do anything:
Tonight, I added quite a bit of infrastructure to support "states". These will be various conditions that can affect an entity such as stun, rooted, and blind. This is implemented by a bitmask. Next, I added a PassiveTrait for stun that makes it easy for Abilities to apply a stun that lasts 3 turns and then removes itself. Whlie stunned, an entity basically forfeits it's turn. Finally, I added some UI to the EntityCanvas to visualize the current states.
My night class has been cramping my gamedev style, but I managed to add a little feature tonight: kill streaks.
Pretty straight forward: kill any entity on your turn, increment the kill streak. Don't kill anything, streak resets. The neat thing, if you can call it that, is that the kill streak is a ResourcePool, just like HP or Action Points. This means it can become a dependency of certain attacks ('have a kill streak of 2+') and I can optionally make some abilities 'consume' the kill streak. Not that I've actually used those ideas anywhere yet.
I might end up not using the yellow UI meter to visualize the kill streak; it's probably overkill. I think putting a simple # on the abilities that require a certain KillStreak might work. But it's good for debugging at least.
Pretty productive day all around:
The action-cost mechanic was a little over zealous. It consumed the action cost of the ability as soon as you selected it, even if you aborted it and chose a different ability later. Now, the ActionPool is passed to the ability, and the ability can decide when to consume the action points. For targetable abilities, this won't happen until you choose a valid target.
Converted HP to the same class as the action point pool. Also added a red UI representation.
Added the concept of PassiveTraits. These are things that, unlike Abilities, don't consume a turn. Though, they may 'tick' every turn like Abilities. I've derived one implementation so far, ActionRegenTrait. It simply gives the player 1 action point back at the beginning of every turn.
I added a concept of "Action Points" which will be the main resource the player has to manage. It will be a cost associated with every ability, and will (hopefully) make the game tactical and fun.
Today I got the very basics of an Action Cost tied to every ability, an Action Pool managed by the CombatEntity component, and some UI.
I really need to find a 'best practice' for tying things like this into Unity UI. My current way involves a lot of delegates, and it's not so bad. But I still find the 'plumbing' to get all the references to each other very tedious. There has to be a better way..
Anyway: onto the gif!
Well I solved the 'cant kill blobs that are on top of traps' bug. It was a logical error on my part, and I'm pretty 'okay' with it as far as bugs go. Then I noticed a very similar bug where enemies that moved onto a trap on their turn wouldn't die ... sometimes .... Sometimes they would. That turned out to be a race condition with syncing up 2 parts of the ability visualization: the animation (which fires an animation event) and the delay I configure into the ability. Basically, if the length of the animation was equal to the delay, it would almost always work. Except sometimes it just wouldn't. I made the delay .05s longer than the animation takes, and it seems to be 100% reliable (in an admittedly small test).
But the bugs didn't stop there. I found a bug where, if you manage to kill yourself on your turn (walk into a trap with 1HP) you don't technically complete your turn, so the game hangs. This is less consequential for the player (game would be over anyway), but it is also true for suicidal blobs. I added some more logic to the TurnManager to detect this case, and it seems to be fixed. But I'm getting kinda leery of all the bugs I've seen in such a short amount of time. I think I might have to refactor exactly how generic my Ability system is, in the name of reducing bugs.
Nothing major done today but I did manage to squash a bug. Under some circumstances, some entities appeared to be getting an extra turn per global game turn. Sometimes it was the player, other times it was a blob or trap. Turns out, it was because of the way I was managing and deleting entities when one died. Without getting into details, I thought I was being clever, but I was not. I think I have it fixed, though it's not an elegant fix at all.
I was all proud of fixing that bug, only to notice a totally separate (I hope) bug. When a blob is on top of a trap and the player shoots him in a way that would kill him, he lives on! His UI even says 0hp which, you never see on normal blobs. If you shoot him again (and he's not standing on a trap) he dies correctly. I'm not really sure what is going on, and I'm still getting over my cold, so I'm gonna call it a night.
Call it a draw: Nick : 1, bugs; 1