Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411507 Posts in 69374 Topics- by 58429 Members - Latest Member: Alternalo

April 25, 2024, 11:59:31 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityDevLogsAutopanic
Pages: [1] 2
Print
Author Topic: Autopanic  (Read 4897 times)
dklassic
Level 0
**


View Profile
« on: August 24, 2022, 01:45:56 AM »

Update - September 19th, 2023

Autopanic's development will be postponed indefinitely.

That said, I still intend to release it, just that the next update on the project will be when it is fully finished. For more detail see: https://forums.tigsource.com/index.php?topic=73644.msg1460282#msg1460282


Update - August 11th, 2023 - Demo end

Gathered quite a lot of feedback during the event. Thanks all of you who've played!

Update - August 5th, 2023 - Demo available now!
My game Autopanic's demo is now available as part of Tiny Teams 2023 (8/3~8/10 BST)!

There are certainly still mechanics missing, but the public demo will feature around 50% of content and 80% of the mechanics. So if possible, please check it out and share your thoughts with me!

Thanks in advance!

Update - June 9th, 2023

Progress has be reduced to reflect the fact that a major design flaw exists, or the lack of design instead.

I'll have to go back to the drawing board and improve the core gameplay before I can call it a day.

A quick gameplay preview


I'm currently making a fully diegetic minimalist twin-stick shooter with Rogue-like elements.

Setup

An AI assistant wake you up from a long slumber. All you can do is to follow its guidance and ascend to the top floor.

Goals

I find 13 Sentinels: Aegis Rim combat visual to be simple and effective, but the combat design itself leaves a lot to be desired. So I wanted to make a twin-stick shooter with 13 Sentinels: Aegis Rim's visual. That's it!

The game eventually evolves into a game with Rogue-like elements because I wanted to make the game about overcoming impossible odds.

Devlog

I'm doing the devlog retrospectively because I started with zero game development knowledge and stumbled a lot during my development. Only now when the game is nearly finished, I can finally sort my development out and write a cohesive story documenting it.

Visual Design

Since I started this project with zero knowledge about 3D and art in general, I limited myself early on to use only vector graphics and 3D primitives throughout the game.

This decision also has impact on my design. Sometimes I give up on a design only because of my visual design toolset couldn't do it justice. In the end this design choice helped my game to be focused.

Fully Diegetic

For no apparent reason, I've decided to make every single element in my game to be diegetic, as in, existing in the game world. To simply put, for whatever stuff player is looking at, that thing actually has a meaning in-game.
Some quick examples:
  • Instead of just a button prompt, the prompt is your buddy AI speaking to you.
  • Instead of characters speaking to each other without voice acting, they are communicating through text.
This design choice caused quite some issue later on, but overall I think it should result in an interesting experience.

Unity 3D

I'm using Unity3D for the development. I try to avoid 3rd party plugins with the exception of DOTween for easy tweening operation and Shapes for vector graphics rendering.
« Last Edit: September 18, 2023, 08:04:59 AM by dklassic » Logged

dklassic
Level 0
**


View Profile
« Reply #1 on: August 25, 2022, 02:53:04 AM »

Prototype

April 2020, inspired by A Short Hike, I decided to start learning how to making my own game. I started with Sebastian Lague's Twinstick Shooter Tutorial and quickly build up something almost enjoyable:

I also accidentally let the projectiles knockback my shooter enemy, resulting in some cool Shoot & Retreat moment.
I think to myself, wow, seven days and it is already fun. No doubt I can make a game!

So I initially planned the game as a shoot 'em up, and the plan is to finish the game in May 2020.
Looking back, that was definitely possible, just not for me back in 2020.
« Last Edit: October 23, 2022, 12:16:15 AM by dklassic » Logged

dklassic
Level 0
**


View Profile
« Reply #2 on: September 05, 2022, 08:39:28 PM »

Early Design

The first iteration of the game is naturally a Shoot 'em Up. Fighting hordes of enemies in a cityscape.

The game is supposed to be about recurring challenge, with some bosses as checkpoints that grant you permanent upgrades.
This is also when the "Fully Diegetic" idea started to kick off. I want players to have a companion commenting on their every defeat (which I didn't know Hades do this back then), and by defeat, being actually dead.
And since after death players have to restart the whole run, naturally they need to recollect their gear from their corpse.
A bit souls-like vibe maybe?

There's also an idea about strategically placing your corpse as a back up for more shield/health to recover during fight.


Scope Change

Because of course there's a scope creep for every beginner's project.
I thought to myself that a game about clearing hordes is not going to sell in 2020, which is later proven wrong by recent success of Vampire survivor. (Had some fun revisiting this idea, but that's for later)
And my initial design revolves around player having an ability to run faster than enemies, which of course makes player completely invincible. So I thought to myself that I need a smaller level. For god knows what reason it never occurs to me that I can add a stamina system which surely works well in Jakob Wahlberg's project GoMechaBall.

Twinstick shooter in small rooms. Time to build a Rogue-like dungeon crawler of sorts.
« Last Edit: January 20, 2023, 08:50:53 AM by dklassic » Logged

dklassic
Level 0
**


View Profile
« Reply #3 on: September 07, 2022, 09:02:12 AM »

Early Level Design with Wave Function Collapse

I was quite obsessed with Oskar Stålberg's games back in August 2020. Bad North and Townscaper both proven to be some decent piece and showcase the randomly generated with authored visual potential of Wave Function Collapse quite well.

So I tried my hand at writing one such algorithm over several attempts with some success.
Then I proceed to scrap the idea of using WFC.

The reason being although I'm starting to generate some unique geometry (as in not seem like tiles), they never hit any sense of meaningfulness in visual. Oskar Stålberg also implied that Bad North has 200+ pieces of models to be synthesized. As a total amateur in game development in every sense, there's no way I can match that.

The actual level design (or the lack of) will come in much later in development.

Here are some of the WFC efforts:

« Last Edit: September 08, 2022, 10:28:06 AM by dklassic » Logged

dklassic
Level 0
**


View Profile
« Reply #4 on: September 09, 2022, 02:56:01 AM »

Early Visual Design

I wanted to do something that is dirt cheap and effective, though I don't really know where I'm going. But I quickly established the style with heavy depth of field and the use of dynamic lighting.

Then I tried an ambient occlusion heavy visual that focuses on color palette swapping. Which almost stayed till the end.

But then the level geometry increased around this time, so I tried my hand at decorating the levels with Unity Particle System. Which I still think looks pretty rad.

Early combat visual also features tons of particles.

However as I slowing move towards a much simple visual choice with most of the visual stuff done with primitives using Shapes, I began to tone down the visual density again.

Since I'm not hitting any jackpot, I decided to work on something else before revisiting visual design.
But this initial attempt solidifies several thoughts:
  • Dynamic elements is much effective than geometry density, such as dynamic light source
  • Since I'm incapable of creating any effective model, I should resort to only primitives
  • Color palette can be effective enough in delivering a vibe
« Last Edit: October 18, 2022, 06:44:58 AM by dklassic » Logged

dklassic
Level 0
**


View Profile
« Reply #5 on: September 10, 2022, 09:48:10 AM »

Minor Burn Out

It is January 2021, my three-month project has stretched into 8 months and I'm not anywhere near the finish line. Actually, I'm not getting anywhere.
But I'm much wiser now, armed with some actual proper game development knowledge and starting to get a grip of what Unity can do properly.

By what Unity can do, I mean it can't do anything. So no more hacking with existing solutions, I must get my hands dirty and start building reliable stuffs. Everything by myself from ground up, so I can know its limitation and know how to expand and fix it.

I decided to build some proper backbone for the project to go forward then grant myself some much needed rest. So I started building:
  • Enemy AI
  • Level Management Tool
  • UI Framework

I'll have to start talking from UI though.

Custom UI Framework

Back then I'm all sold on the new Unity Input System, which has some really promising features and I don't want to walk back to use the old input system. However the new Input System for whatever reason doesn't gel well with their UI Events.

So I need a custom UI framework.

Inspired by Phi Dinh's Recompile, I figure a fully text-based UI would be great for my project.
Although I'm incapable to do fancy ASCII animation and having to support Chinese characters by default ('cause, I speak Mandarin) removes quite a lot of  presentation choices, limiting myself can help me focus more on actual useful stuffs.

Building a robust UI framework is imminent anyways because before that I was debugging by clicking on Unity's editor window. The back and forth between game screen and editor takes me out of the flow, traversing the scene hierarchy doesn't help either.

I started by building an enemy spawner:
An elegant weapon for a more civilized age.

This makes the enemy testing process much easier. No more drag & drop and clicking through scene hierarchy.

The UI framework gradually grows into a behemoth supporting all sorts of stuffs easily. For example, my system menu UI can be initiated with a class that inherits the GeneralUISystemWithNavigation class. Then I can simply do:
Code:
    protected override void InitializeUI()
    {
        systemWindow ??= NewWindow("ui_system", DefaultSetup);
        AddButton("ui_system_Resume", systemWindow);
        AddButton("ui_system_Visual", systemWindow);
        AddButton("ui_system_Audio", systemWindow);
        AddButton("ui_system_Control", systemWindow);
        AddButton("ui_system_Accessibility", systemWindow);
        exitUI = AddButton("ui_system_Exit", systemWindow);
        systemWindow.AutoResize();
    }

And then vuala:

I can also easily define the button's function as such:
Code:
    protected override bool ButtonAction() => currentSelection[1] switch
    {
        0 => CloseMenu(true, false),
        1 => OpenSubMenu(0),
        2 => OpenSubMenu(1),
        3 => OpenSubMenu(2),
        4 => OpenSubMenu(3),
        5 when exitUI.Available && !endgame => OpenSubMenu(4), // spoiler?
        5 when exitUI.Available && endgame => OpenSubMenu(5),
        6 => OpenSubMenu(4),
        _ => false
    };

Though all the game's UI are done with this framework, my debug menus made the most out of this framework:

Building this set of UI framework really helps a lot further into development. Though I have to live with the consequence of difficult to do mouse detection later on.

Mouse Detection Difficulty Update - September 11th
Well, turns out I've been scaring myself all these time.
Since my UI system is brute-forced with Unity's Text Mesh Pro, I thought I need some shenanigans or drastic rework to make mouse detection possible.
Turns out TMP can simply retrieve the anchor of each character. So I just record the anchor and check if the mouse's screen space position is within that range, and then it is done.


Probably a bit costly when initializing a large menu (like my debug menu) and not as intuitive as typical raycast approach, but it seems to work just fine.
Hurray!
« Last Edit: September 11, 2022, 10:09:18 AM by dklassic » Logged

dklassic
Level 0
**


View Profile
« Reply #6 on: September 18, 2022, 12:40:12 AM »

AI Behavior Revamp

My old solution relies on Unity's NavMesh and NavMeshAgent. This becomes a chore to me later on because:
  • As my levels becomes more dynamic, managing NavMesh becomes a tedious work
  • NavMeshAgent can reliably move towards the destination, but also costs too much to request frequently
  • My gameplay is very fast-paced, so I'd like my enemies to react to player action as fast as possible
So I decided to move to a custom solution that is basically about picking a preferred direction and move forward.

Movement Determination

Generally a level may look something like this:

For each calculation, the agent will check the following things:
  • Obstacle around the agent (e.g. other agents, traps, and decors)
  • Distance and direction towards a preferred location (e.g. movement destination and target agent)
So it's all about avoid bumping into obstacles and wanting to have a certain distance between certain target. Which looked like this:

Then I added some physical constraints to make the agent move more naturally, such as:
  • Having acceleration/deceleration speed
  • Having max speed
  • Will decelerate if the preferred direction is too different from current direction
  • Have a max rotation speed
I could've gone further and have rotation acceleration/deceleration, but I find it somewhat hard to balance around the numbers, so I've decided to omit it for now.
So far so good:

This approach also helps me make some actions more dynamic, such as "Strategic Dash" and "Emergency Evade", for these action can now be used with understandings of the environment instead of a fixed direction and stuffs.
I've then spend some time optimizing raycast with multithread but nothing fancy.


Attack Pattern

I decided to move towards the idea of an attack pattern. To ensure the combat won't become raw skill-based chaos, but a more manageable situation to be learned and resolved by the players.

So I constructed a hefty list of actions available, just to name a few:

And now instead of making multitude of enemy prefabs, I now have one enemy prefab that will instantiate with a EnemySetting scriptable object, which makes modification a lot easier.

Now with enemy behavior revamped, time to add in procedural animation.
« Last Edit: October 23, 2022, 12:26:19 AM by dklassic » Logged

dklassic
Level 0
**


View Profile
« Reply #7 on: September 24, 2022, 10:21:28 AM »

Procedural Animation

Procedural Animation in my game is a big topic, because basically every single changing element was procedural, i.e. code driven.
I know early on that I'm not going to be doing keyframes at all. Not only because I'm just but one guy, also that I've watched the famous talk from David Rosen about procedural animation in Overgrowth and was convinced that procedural animation can be used to achieve suitably high quality animation with way less effort.

UI Animation

Not much to talk about here due to my simple UI setup, but I do have several glitch effect setup for the windows, which is driven by something like this:
Code:
switch (CurrentTransition)
{
    case WindowTransition.Noise:
        maskIndex[i, j] = UnityEngine.Random.Range(0, TextUtility.FadeIn.Length - 1);
        break;
    case WindowTransition.Glitch:
        if (UnityEngine.Random.value > 0.5f)
            maskIndex[i, j] += Mathf.FloorToInt(Time.unscaledDeltaTime / maskAnimationStep);
        break;
    case WindowTransition.DamageGlitch:
        if (UnityEngine.Random.value > 0.5f)
            maskIndex[i, j] += Mathf.FloorToInt(Time.unscaledDeltaTime / maskAnimationStep);
        break;
    case WindowTransition.Random:
        if (UnityEngine.Random.value > 0.25f)
            maskIndex[i, j] += Mathf.FloorToInt(UnityEngine.Random.Range(1, TextUtility.FadeIn.Length - 1) * Time.unscaledDeltaTime / maskAnimationStep);
        break;
    default:
        maskIndex[i, j] += Mathf.FloorToInt(Time.unscaledDeltaTime / maskAnimationStep);
        break;
}

Some demonstration:

Generic Procedural Animation

This part is a bit more fun. Mostly done with DOTween because DOTween is just great. Some examples:
Hit Reaction:
Code:
icon.DOPunchRotation(damageForce / unitSize, 0.5f, 10, 0)
Weapon Recoil:
Code:
recoilTarget.DOPunchPosition(recoilForce / unitSize, recoilDuration, 1)

Simple, quick to make, and can include the consideration of physicality quite easily.

Procedural Movement Animation

Now comes the fun part, though maybe not much to be explained.
I find that making procedural movement animation is basically programming the process of how the real world counterpart would move:
  • If leg is too far away, move
  • If moving, lean
  • Move faster if displacement is large
Which is as rudimentary as it can be, but this also makes it hard to find resources to follow. I ended up learning more about procedural animation by looking at Jakob Wahlberg's tweets.

Since I revamped enemy behavior, my AI now have some proper physicality in its movement. So as long as my procedural movement animation can automatically accommodate the displacement of the unit, the result will always be great:

And by extension, it also works on player controlled character:


So with procedural animation in place, my game finally looks a lot more complete.
« Last Edit: October 23, 2022, 12:29:51 AM by dklassic » Logged

dklassic
Level 0
**


View Profile
« Reply #8 on: October 10, 2022, 01:41:41 AM »

The Lack of Level Design

I'm quite inspired by Oskar Stalberg's work on Bad North, and I remember seeing him mentioning the level design.
Can’t remember the exact quote and I forgot which tweet does it come from, but I think it is something like this:
Quote
Every randomly generated level is a valid test of player's combat skill

It was a tweet about how WFC can be easily utilized in a combat-focused game but not so much in a puzzle game.

Anyhow, I decided to follow this philosophy so that I can quickly went over level design and focus on other pressing matters.
So I first started by making a level editor:

Tried and true 2D checkbox, easy. My idea is to make some generally serviceable shapes then use random decoration to fill up the space. I'm not going to impress players with fully unique level visuals so I just simply do none.

By randomly spawning decorations in level, essentially an unique combat puzzle has spawned.
I prepared several types of decoration:
  • Pillar - Blocks everything, can be destroyed
  • Railing - Blocks non-flying units, serves as a dynamically spawned gap
  • Trap - Just some explosives

To prevent random decoration killing the experience, I've added some additional rules:
  • Max amount of decorations allowed is root squared tile count
  • Decoration can only spawn if that tile has at least six neighbor tile
  • Decoration cannot spawn if any neighbor tile has decoration
  • Decoration cannot spawn if adjacent to Exit tile or Entrance tile
Worked out pretty well.
Not that this will generate any memorable encounter on its own, but it indeed change the flow of the level drastically enough to produce unique combat puzzle on every random generation.


This approach also allows me to preview all layouts easily in my UI system:


Level Visuals
I'm definitely not going it impress anyone, but I hope to provide some interesting floor patterns to be discovered during gameplay. These patterns will be revealed dynamically whenever a light source shows up. I find this approach easy to make yet still feels interesting to see them through the crack of light.
« Last Edit: October 21, 2022, 09:05:42 PM by dklassic » Logged

dklassic
Level 0
**


View Profile
« Reply #9 on: October 12, 2022, 07:40:46 AM »

Quick Vacation

Following the minor burnout and finally cleaning up lose ends and laid out some great foundation, I took a three month break to do something else. Like making more games.

Enemy Within
I made a small game about card. Quickly hacked together nice looking setup with HDRP example scene and had some physics fun.

Taipei Bus Rush
There's this long running joke about bus drivers are driving as if they're racing in Taipei. Only that it is not actually a joke.
Anyways. I then made a game about roaming around Open Street Map generated Taipei with a bus. Collecting passengers at bus station then boost by throwing passengers out. I tried to generate all the racing course with existing bus route. Fun one.

But then I thought I found a gold mine: Tokyo's OSM marking is surprisingly robust, what if I can generate the whole city then make some quick bucks?

Open World Tokyo

In short, huge mess. But I learned so much from it.
Though OSM marking of Tokyo is pretty robust, the data is pretty difficult to use outside of plain 2D map.
The most difficult part is to solve intersections and generate road mesh, which is extremely hard so have universally good result with a single ruleset.
For example, here's a good one:

Here's one less so:

Real world roads are complex and hard to generate road mesh with one single ruleset. And this is probably the hardest part of cloning real world Tokyo.

This attempt also made me look more closely to Microsoft Flight Simulator's result, then found out that their result is no better than mine:

What a relief!
Anyways I still managed to produce some serviceable background level stuff, and hopefully I'll one day actually deliver on this idea.

What matters is the shaders we learned along the way
Before this, I was afraid to write shaders, but with this three month vacation, I tried my hands at Unity's Shader Graph to make shaders.
I have no knowledge of 3D modeling and I figure I should try to decorate everything with shader. I learned to make procedural building exterior shader. I learned to make road wet with simplex noise:

Even tried my hand at mimicking Falconeer's approach overriding the whole lighting system and made a submerged version of Tokyo using shader alone:

I have so much fun making shaders during this three month period, and I'm now convinced that shaders can do ANYTHING!
Which helped me a lot later on when I wanted to make better scenery for Autopanic.
« Last Edit: October 23, 2022, 01:36:59 AM by dklassic » Logged

dklassic
Level 0
**


View Profile
« Reply #10 on: November 13, 2022, 10:48:08 AM »

I'm really getting this post clogged up with GIFs huh.

Welp, time for more. Sorry not sorry.

Anyways, I'm very inspired by the famous "The Art of Screenshake" talk and my gameplay is basically derived from that talk.
So this post will be a break down of all the juice added to the game.
Before
After

Before that, you may download this special build of the game featuring an array of tools to toggle on/off juice:
https://dkliao.itch.io/the-art-of-screenshake-recreation

And here's a rapid fire of comparison GIFs.
Baseline

With Animation

Lower Time to Kill

Increase Rate of Fire

Increase Bullet Size

Muzzle Flash

Faster Bullet

Lower Accuracy for More Dynamics

Impact Effect

Hit Reaction

Enemy Knockback

Permanence

Camera Lerp
↑Lerp Off
↑Lerp On

Screenshake

Player Knockback

Hit Pause
↑Hit Pause Off
↑Hit Pause On

Weapon Recoil

Random Enemy Explosion


Anyways, that about wrap up my gameplay.
« Last Edit: December 05, 2022, 05:06:09 PM by dklassic » Logged

mobilelast
Level 2
**


View Profile WWW
« Reply #11 on: November 23, 2022, 11:15:13 AM »

It is always interesting to read insights about Unity-development. Very familiar thoughts to myself too.

The sentence “Sometimes I give up on a design only because my visual design toolset couldn't do it justice.” caught my eye, since it is a good guideline in the arts in general. Sticking with the dogma keeps things coherent and focused, but it is surprisingly hard to stay faithful to the original idea when new ones keep coming and coming.

Looks like you’ve traveled far from the beginner level. The game itself is very pleasing to the eye, game elements are clear, and you really know your tweenings. As an additional hint: familiarize yourself with Mathf.Perlin -function (there are lots of tutorials all over how to utilize it). It can make random elements much more controllable and interesting than generic random noise (Random.value).

Great stuff. I’ll be following.
Logged

Avaruustaistelupeli (ATP) - a space combat game
- Free download from itch.io or IndieDB
- Dev diary here
dklassic
Level 0
**


View Profile
« Reply #12 on: November 23, 2022, 05:27:17 PM »

It is always interesting to read insights about Unity-development. Very familiar thoughts to myself too.

The sentence “Sometimes I give up on a design only because my visual design toolset couldn't do it justice.” caught my eye, since it is a good guideline in the arts in general. Sticking with the dogma keeps things coherent and focused, but it is surprisingly hard to stay faithful to the original idea when new ones keep coming and coming.

Looks like you’ve traveled far from the beginner level. The game itself is very pleasing to the eye, game elements are clear, and you really know your tweenings. As an additional hint: familiarize yourself with Mathf.Perlin -function (there are lots of tutorials all over how to utilize it). It can make random elements much more controllable and interesting than generic random noise (Random.value).

Great stuff. I’ll be following.

Thanks for your reply!

I think I got that mentality of design based off visual toolset out of Into The Breach's postmortem, where the creators stated that they give up designs if they can't have a simple way of telegraphing it. This mentality really helps me to focus on what I have instead of endlessly chasing ideas.

Also thanks for mentioning Mathf.Perlin, I've been using Perlin Noise for a while but only in shaders, sure seem like a better way to do certain elements, will try to utilize it!
Logged

failbetter
Level 0
**



View Profile
« Reply #13 on: November 26, 2022, 09:30:30 AM »

Great devlog and incredible progress, thanks for sharing!
Logged

You may defeat me today but I will return stronger tomorrow.
sandsturm
Level 0
*



View Profile
« Reply #14 on: November 30, 2022, 03:56:16 AM »

Please, keep us updated!
Logged
dklassic
Level 0
**


View Profile
« Reply #15 on: December 17, 2022, 11:49:36 AM »

Thanks for all the reply! Hopefully I'm producing something interesting to read.

So, I want to do another sidetrack to talk about a spinoff project. Yep, as an indie developer of course I have to do new project before finishing the original project.

A project made in 7 days
Back in May I submitted Autopanic to a local contest, which I earned third place. The prize comes with a guaranteed coverage by biggest local gaming news site so not bad. But I digress.

After submission. I decided to take a break and play this "Vampire Survivor" everyone is crazy about, and oh boy, ain't it some of the best balancing I've ever seen.
The thing that surprised me most is probably how this kind of Shoot 'em Up ish design still holds up and people now crave for more. So, I decided to try my hand at revisiting the original idea of this project, but with some Vampire Survivor's design in mind. I then proceed to recreate my original idea for my game in seven days.

Though before that, I need to fit larger enemy count into my game.

Switch to manager pattern
Since enemy count is drastically increased, I need to squeeze out every single performance.
I've always use the Update() function in Unity to do everything, but according to Unity's own article, such method introduce overhead when used a lot.

I've already have an EnemyManager to do all the spawning and despawning, so it's just a matter of using it to update all the enemies. Which is easy enough.

Jobs for raycast
Since my AI relies on massive raycast count to decide its movement, large enemy count naturally results in some absurd amount of raycast. Here's a quick look at 100 enemies' raycast:
Actually, not bad! But we're talking hundreds of enemies here, gonna optimize it as much as I can or else players will shower negative review all over the internet.
So naturally I tried to use Jobs for multithreaded raycasting:
And...... the performance got worse. Which is expected since I implemented this jobified version the same as before. Each enemies still cast their own rays, just batched into a job. It would seem like when the ray count is low, batching it with job actually worsen its performance.

So let me try again. This time with the manager pattern, I use the EnemyManager to cast all the rays for all enemies at once, and then:
Now that's an improvement!

I also ported this design back to my original game, which don't actually need such efficiency but hopefully some players would be happy about it.
Also watching large amount of my enemies swarming though the map is quite satisfying.
Logged

dklassic
Level 0
**


View Profile
« Reply #16 on: December 24, 2022, 09:02:01 PM »

So, as a solo developer, it's extremely hard to juggle with all the numbers for balancing.
To help me with that, an automated tester was deployed to help me quickly validate my design changes.

Here's a snippet of it in action:



Auto Tester
I first have the idea of automated testing since my revamp of player and enemy code base. Although still separated, a lot of the designs for player and enemy were structured to be similar. I quite fascinated by some automation test talks from GDC, and figure it should be extremely useful for my game to have one. Though I never went the extra mile to setup an automated test, my later systems are often written with automated tests in mind.

Fast forward to me making a spinoff project, I only want to hack together something somewhat enjoyable as fast a possible. But Survivor-like gameplay takes quite some effort both physically and mentally to play through, and it is also extremely time consuming to do playtest myself. I'm not quite ready to lose my friends to an unbalanced gameplay so I decided it's time to deploy an automated tester.

Auto Tester for Autopanic Zero
Automated tester for Autopanic Zero is pretty rudimentary. All it does is:
  • Always target nearest enemy
  • Having a preferred distance from target
  • Shoot constantly
  • Initially dash whenever available, I later make it assess how surrounded it is to trigger the dash
But it is already useful enough to validate the general balance before I had to dive in and check the experience in depth. This helped me focusing on broad strokes when tweaking my game instead of burying myself in details.

So I'm quite happy with the results. Still, there's only combat in Zero which makes it trivial to implement, but Autopanic has much more interactions to consider.

A detour at Sigono
For some reason I have the privilege to work in Sigono, the studio behind the excellent OPUS: Echo of Starsong.
I've been helping to port the game to iOS and to save performance in a finished product without full picture of the code base is a trial and error effort. Thankfully they have a automated testing system with automated screen recording which helped me check the result of my tweak without me having to play through the whole game.

Their automated system more than once saved my ass, and solidifies my desire to finally implement automated tester in Autopanic.

Auto Tester for Autopanic
So automated tester in Autopanic is deployed to do the following:
  • Clear an encounter
  • Reach reward and claim it
  • Move towards a randomly selected exit and use it
  • Interact with shops
  • Die
  • Repeat infinitely

The tester tries to mimic an actual gameplay and only teleports when needed (since I haven't implemented a proper path finding algorithm).
It's not smart enough to win the game on its own, but it is robust enough to consistently making to the first boss and occasionally winning. When I really need it to make it to the end, I'll just lock its health so it can power through.

Autopanic is an absurd project for a solo developer if I'm being honest. Some design choices intentionally adds burden to the  system, zero load screen and no cut policy isn't something I'd recommend trying without proper experience, but that's where I am right now. So the deployment of automated tester really helped a lot, and has since helped me with:
  • Continuously sanity checking the healthiness of the code base and the overall performance
  • Infinite retrying to help identify rare bugs
  • A quick validation of the overall game balance
  • A quick method to generate believable gameplay and screenshots without me having to play

Automated testing is basically free quality assurance workforce. I think small developers will benefit a lot from deploying one.
« Last Edit: December 25, 2022, 10:02:53 AM by dklassic » Logged

dklassic
Level 0
**


View Profile
« Reply #17 on: April 24, 2023, 11:27:00 PM »

It's been quite a while since I last posted so I guess time for a quick update.

Back to business

I've left SIGONO and now work in a freelance capacity to help them keep track of all sorts of optimization.

There's not much I can do with my own game when I'm working another job fulltime, so it's been mostly just optimization of all sorts instead of actual game designing for the last six months which requires a continuous chunk of time to perform.

Anyways not really much to show, but I decided to make a proper starter room albeit a rudimentary one:


Whenever player died, there are multiple dialogues that can playout:
  • Death Comment
  • Story Dialogue
  • Combat Suggestions
  • New Weapon Hint

Death Comment will always playout, but originally the rest of the three will only show one. The reason behind it is because I'm not committed into designing a starter room beforehand, the starting room used to look like this:


So, just an even more barebone square room with an exit readied already.
I wanted to let players discover more about the story/gameplay mechanics gradually and naturally instead of text dumping them, and to prevent dragging for too long only one can be shown in the starter room, with the priority being: 1. New Weapon Hint 2. Combat Suggestions 3. Story Dialogue.

But this is quite a problem for a game that is already pretty short, and I don't want players to miss out the story dialogue too much. So instead now all three dialogues will have its own timing to be played out.

The New Weapon Hint will always play, otherwise players won't notice. The Story Dialogue can be triggered by interacting with your buddy, which prevents other dialogues to preempt Story Dialogue too much if the player progresses too far, and also allows players to bypass it if they wish to do so.

The exit is now an elevator-ish thing, so I can slot in the Combat Suggestions naturally like it's a loading screen or something:

Works left

The game is still 90% finished like last year when I started posting this thread, but now it is polished to the extreme with almost every rough edges cleaned up. Most problems that I don't aim to clean up for this project ends up being solved in the past six months bc I don't have time to progress the 10% left. Fortunately whenever I tried to push through these seemly unsolvable tasks at a glance, they all end up being cleaned up quite easily.

I'll probably do a character redesign soon and then start pushing more rounds of playtesting to see if I hit the mark or not.

Hopefully releasing this Fall, hopefully.
Logged

dklassic
Level 0
**


View Profile
« Reply #18 on: June 01, 2023, 08:33:36 PM »

Autopanic is now in the phase of mass external playtest, so that I can get a better grasp if my designs are working or not. Accompanying extensive playtest sessions, I'm now required to switch between different features constantly and starting to make a lot of mistakes building and uploading the wrong version.

Time to make an auto builder.

The Features


Currently there are several features for Autopanic:


  • Debug Start Up, instead of the usual loading the game normally, give me several options to quickly setup my test environment.
  • Allow Debug Tool, should be self-explanatory.
  • Allow In Game Logger, display additional info on screen for testing purpose.
  • Allow Incompatible Save, save conversion between versions doesn't exist yet, by default I simply purge incompatible save.
  • Skip Tutorial Setting, my tutorial starts with a sequence of settings, to save me some pain here's a skip.
  • Allow Steamwork, since Steamwork messes with the editor, it's forced off by default but sometimes I need to test it in editor.

These correspond to some of the following scenario:

  • Personal playtest session uses every combination.
  • External playtester will play out normally, but I want them to be able to access debug tool just in case.
  • To test on Release version, the internal debug log will have to be shown on screen.
  • Sometimes I'll have to remove Steamwork and pack the game in a zip.

So with great features, comes great responsibility to remember which is for which, and remember to setup correctly before exporting the game. But with the extensive playtest, I now make enough mistakes for me to decide to offload it to an Auto Builder.

Auto Builder


Simply put, to setup a one click building tool that exports the project with the right setting.

Unity's editor tool allows for the access of UnityEditor.BuildPipeline.BuildPlayer to trigger the build, and UnityEditor.PlayerSettings.SetScriptingDefineSymbols to setup the define symbols. So that's it:

  • Change the define symbol
  • Build the game
  • Revert the define symbol

Done.

Well, not quite.

Auto Versioning

Autopanic is an extremely small game, both in terms of content and assets included. The game built is around 200MB which can be compressed into 70-80MB, the build process takes 20 seconds with Mono and 1 minute with IL2CPP, which is absurdly fast .

So I can quickly iterate on my design and playtesters can receive patches as soon as reported. But with fast iteration comes the problem of actually knowing which version playtesters are on. Steam doesn't notify each client instantly for patches unless the user verifies game file manually, so I need to mark versions properly to know if the problem has already been fixed or not.

But well, let's just say I'm not going to bump that Application.version every time I build, so I need some automatic way of versioning. And here's where the version control comes in.

See, Git tracks each commit with a SHA value, which is almost guaranteed to be unique even with just the first few digits. So I just need to read the .git folder and get the SHA every time I build, and say, maybe also every time I enter play mode.

Of course this comes at the cost of increasing the time required to enter play mode (RIP my super fast enter play mode time), but it should more then make up for actually knowing where I am, in terms of my code, all the time.


Anyways, back to playtest and iterating!
« Last Edit: June 01, 2023, 08:39:44 PM by dklassic » Logged

dklassic
Level 0
**


View Profile
« Reply #19 on: June 08, 2023, 05:55:01 PM »

Back to drawing board

Playtest is both great and not so great.

It's great that all the fully diegetic bull I'm pulling seems to work, against all odds. Playtesters genuinely find the design to be interesting enough. The not so great part is that the gameplay itself is deemed flat and uninteresting especially among the veteran roguelike players, and the gameplay is something I thought I'm supposedly done with a year ago.

At first I felt like my designs are failing, but upon close inspection I figured out what exactly went wrong: not the design, but the lack of design.

I quickly recalled my game is just a twinstick shooter strapped with the fully diegetic premise, then to accommodate the ability to acknowledge player death, a roguelike structure is then slapped on top of it. But the gameplay itself was never designed with roguelike in mind.

Sure, I've got random rooms, enemy compositions, abilities, and a respectable amount of weapons. But the core gameplay loop, using the guns, poses no synergy whatsoever. There's no risk/reward at play here, so of course the gameplay doesn't feel interesting enough as a roguelike, it never was designed for a roguelike.

At least I finally got myself unblinded from the illusion of my job is done, instead of a regression of progress, I've probably progressed much more than I would've without this playtest session. And now I can dive back in, to actually make designs for a roguelike.

The goal

Truth to be told, I feel like most of the surrounding stuffs are good enough, so I'd be focusing more on revamping the core gameplay itself.

I've got plenty weapons and the ability to wield two, but they don't have any synergies between each other. I'll try to change to a single weapon only design but with two attack mode, so that I can design the two modes to be compensating each other, allowing players to do riskier moves in exchange for far greater damage.

Should be instantly more fun than before if I pulled it off.
« Last Edit: August 04, 2023, 07:33:55 AM by dklassic » Logged

Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic