CODE:
g = GUI.Canvas()g.add(GUI.Window("Universe Configuration") .add(GUI.Checkbox("Infinite Mode").bindTo(&config.infinite)) .add(GUI.Slider("Average Systems Per Region", 10, 1000).bindTo(&config.regionSize)) .add(GUI.Slider("Average System Connectivity", 1, 10).bindTo(&config.connectivity)) .add(GUI.GroupHorizontal() .add(GUI.Button("Create", createUniverse)) .add(GUI.Button("Cancel", cancelUniverse)) ))...g.update()g.draw()
CODE:
GUI.BeginWindow("Universe Configuration") GUI.Checkbox("Infinite Mode", config.infinite) GUI.Slider("Average Systems Per Region", 10, 1000, config.regionSize) GUI.Slider("Average System Connectivity", 1, 10, config.connectivity) GUI.BeginGroupHorizontal() if (GUI.Button("Create")) createUniverse() if (GUI.Button("Cancel")) cancelUniverse() GUI.EndGroup()GUI.EndWindow()
Statistics: Posted by JoshParnell — Sun Aug 19, 2018 1:48 am
JoshParnell wrote: ↑Sat Aug 11, 2018 6:54 pmWell, I hate doing this, but: I need another week.
My recent work has consisted of moving a major game subsystem from Lua to C, which is an ongoing process as you all know. In doing so, I had to choose between one of two major, high-level architectures, each with very different strengths and weaknesses. Despite having high hopes in the beginning, after having the system solidly in-place, I have only just come to the conclusion that I made the wrong choice. Sadly, it was necessary to have the system up-and-running before I could make the determination that it wouldn't pan out. It's rather heartbreaking, and, while I had planned on simply writing an account of this (failed) work, I feel that my time would be better spent taking the weekend to recharge, implementing the system in the other architectural style next week, and writing about the results at that time. Frankly, I'm too disgruntled and exhausted from work to produce a decent devlog at the moment anyway.
Apologies! If lessons learned the hard way are a currency, then I am a very rich man On the brighter side, I'm sure it will make for a compelling story. Just...not right now
Actually...that kind of mentality always ends up breaking my heart even more, to be honest. And it's where my head was today, which is exactly why I'm choosing to wait -- doing things purely for the log always feels bad to me. I not only feel bad about unsuccessful work, but then I also feel bad about trying to compensate with work that I didn't actually work hard on and am not invested in, but will be judged on nonetheless. It's a dangerous, stressful habit that I hope never to revisitHyperion wrote: ↑Sat Aug 11, 2018 6:59 pmAnother week? Unacceptable! I demand an 8000 word log within the next 15 minutes!
Well could you at least say what system it is, and could we get a shiny or 2 to hold us over? You could say work on graphics for an hour or 2 tonight and still technically deliver something today Might help alleviate the heartbreak too
Statistics: Posted by JoshParnell — Mon Aug 13, 2018 12:10 pm
JoshParnell wrote: ↑Fri Jul 13, 2018 8:11 pmHail, spacefarers!
In today's log, I'm going to afford myself a mental break from talking about the economy again and instead walk you through how to build a universe with interesting structure, which is something that I have been doing recently to take a breather from pricing, economy, credits...it was all starting to drive me a little mad. I spent roughly another two weeks on it all, then decided that I really needed to dip my toes into something else before I started having nightmares about market orders. That being said, I was still thirsting to do something with a 'big picture' feel to it, since I have spent so much time on little pictures, hence this excursion into universe generation! It was a fun process, so I will share it in enough detail that you should be able to build your own universes if you so desire
Starting with Star Soup
Let's jump right in. For our purposes, building a universe consists, essentially, of building a graph (a collection of vertices and edges linking those vertices). Vertices represent systems, edges represent wormhole or jump gate connections between systems.
The most basic starting point is a random collection of vertices, distributed uniformly over a space. This is as boring as boring can get:
Still, we have to start somewhere...
Getting Connected with Kruskal's
If a uniformly-random distribution of points is the most basic way to generate vertices, then the most basic (sensible) way to generate edges is via a technique called the minimum spanning tree. For our purposes, what it means is that we want to 'connect the dots' in such a way that we are using as little 'distance' as possible. In other words, we want to make it possible to navigate from any system to any other system, but we also want to make the connectivity such that nearby systems are the most likely candidates for being connected. When you see it, you'll understand why we want to connect our systems like this
Luckily it's easy to write the algorithm for doing this! There are two great, easy choices: Kruskal's and Prim's. Since the former is slightly more general and I have written it many times before, I will use Kruskal's. They produce the same results when building a single MST.
Here is our soup of stars, this time connected with the MST:
Already looking better!
Notice how the connections are made in a very 'orderly' way. That's because of the MST. Connecting random stars will yield a far less attractive map.
Hierarchical Detail: Regions & Regional Substructure
Clearly, this universe is too boring. We would like to see more structure: stars within clusters within regions, etc. 'Real' physics aside, structure will make for far more interesting gameplay, and a better feeling of getting to explore an interesting universe.
Here's an idea: what if, instead of generating a bunch of uniform stars in a soup, we were to generate a few regions in a soup, then start 'attaching' stars to those regions? Let's try it. We'll generate 20 regions, then 1000 stars, each randomly attached to a region and with a 5% random exponential deviation from the regional center. Then we'll connect it all just like before.
The results are much more encouraging:
Note that I have given each region a random color here, and stars inherit their region's color, purely for the sake of being able to see the regions on this map. We will obviously draw this whole thing in a prettier way for the in-game UI
There are lots of ways we can tune the generating parameters to change the structure. For example, while I like the rather chaotic nature of these regions, you can change the system position-within-region distribution to gaussian instead of exponential to 'tighten up' the regional clustering. Here is what gaussian with 0.7% deviation looks like, using the same seed as above:
And, just for show, 50 regions with 2000 systems (back to exponential distribution):
(Yes, I too wish the colors were prettier...but remember...no getting distracted by...graphics...... )
Generating Shortcuts
At this point, things are looking quite nice. However, if you look carefully at the map and think about navigating around these systems, you may find that it seems quite tedious! Indeed, getting out of a distant 'corner' of space can take a lot of jumps. This is, in fact, by design! The minimum spanning tree is exactly that: it uses the least amount of 'connective line' that we could possibly use to make a connected universe. In particular, there is zero redundancy. Since it's a tree, there is also exactly one (non-overlapping) path from any point A to any other point B, never more. It's an efficient universe in terms of wormhole usage, but it's not very kind to the weary inter-regional merchant!
Looking at these maps, you can probably see 'obvious' places where you could draw an extra connection or two and really cut down on the amount of travel required to get around. For example, here's an annotated map where I've drawn in some obvious choices for extra connections that'd make things easier:
We'd like to generate such 'shortcuts' automatically. But how? Teaching the computer to identify good shortcuts is actually not so easy. We need a way to mathematically define good shortcuts. Intuitively, we want to choose two systems that are topologically far apart (that is, the path between them is very long), but are physically close. You will indeed note that this is a characteristic of all the sample shortcuts I drew above: they bridge systems that are physically close to one-another, but very very far apart in terms of the 'path length' between them.
So, all we have to do, for each shortcut we want to make, is: find the pair of systems whose ratio of travel distance to physical distance is the highest, and connect them. Turns out, this algorithm works really well for the most part. (Note: in reality, I use travel distance divided by the square root of physical distance, which encourages the algorithm to think more globally rather than making intra-regional shortcuts). Here are the first three shortcuts that the algorithm selects on the above map:
Hey! Look at that! Two of the three shortcuts the computer chose made appearances in my annotations (I swear I did not check before I annotated!) Sadly the algorithm did not come up with a space whale option, but it would be difficult to teach the computer to be as silly as me. We'll check out one more example, this time with 5 shortcuts:
I really like these choices
The shortcutting algorithm serves to make the map's structure even more interesting, since we now have more options for getting around, but we have introduced those options in a very specific way based on our goal of providing the most 'bang for our buck' with each shortcut.
Unfortunately, this shortcut algorithm is also computationally expensive. Computing all path lengths on a graph is expensive, and doing so in an efficient way is a significantly harder algorithmic challenge than computing the MST. I've played with a few cheaper ways of computing shortcuts, but none have come up with as good of results. I'm sure that, with a bit more thought and cleverness we could solve this much more quickly. For now, I'm pleased with the results, and will optimize more as I am able.
(Bonus) 3D
It should come as no surprise that all of the algorithms I've discussed extend effortlessly into 3D. In fact, while building the generator, I used 3D math the whole time, but kept a configurable constant that let me collapse the third dimension at will.
For Limit Theory, I have expressed that I will likely default to 2D universe maps; I prefer the simplicity. However, as demonstrated, it's effortless to enable 3D generation, so we can include that as a configuration option in the universe generator
(Bonus) Making it Infinite with Boundary Stitching
But wait! Limit Theory advertises an 'infinite' universe! So far we have only seen finite ones. What's the deal? The deal is quite simple, in fact. To make a universe infinite, all you need to do is 'tile' a finite one -- that is, use your 'finite universe' generator to generate content for each 'cell' of the universe, then find a way to stitch them together. Think of these screenshots we have seen so far as single 'pixels' in the infinite picture of the universe. The only interesting problem with this approach is how to connect the cells. In particular, if we want to make sure that the universe actually does go on forever (and that we can actually get to new systems forever), then we must make sure that the entire grid is connected.
The way to do this is very easy: choose a star system to represent each border of your tile (in our case, for a 2D grid tiling, we could call them N, E, S, W, for example), then connect the borders of adjacent tiles appropriately (the N border-system of a tile will be connected to the S border-system of the tile above it, etc.) To choose which systems should be border systems, there's an obvious answer: the system that is closest to the border (duh?) In other words, the northmost system in a tile will be our N border. To make all this clear visually, we can draw our border systems on the map and extend lines outward to indicate where our universe tile will be stitched to neighboring tiles:
So, when the player is getting to within topological proximity of one of those four border systems, we need to ensure that the appropriate adjacent tile in the universe is generated (and receives enough historical simulation to 'smooth out' border effects). The generator automatically identifies the border systems and flags them as such so that the engine will be able to handle preloading accordingly.
I have actually decided, over the course of LT development, that I don't want to play in an infinite universe, but would rather have a large, finite one (so that I am forced to get to 'know' it, rather than endlessly skipping town to the next cell). That being said, infinite universe generation is clearly one of the promises of LT, so I fully intend to support this tiling / stitching system despite my own preference to play without it (finite/infinite will be yet another universe configuration option).
By the way, in case it isn't clear, one very important property of the border stitching mechanism is that you don't have to generate the neighboring cell to know how it is connected to your current cell. This is in stark contrast to how we generated the finite universes above (we can't find the MST of an infinite graph, for obvious reasons!) This is the fundamental trade-off of infinite generation: you must have some topological regularity at some level. But, you see, we can play this clever trick of making each 'tile' of our regular grid a rather complex structure in its own right, which ensures that we get a much more interesting universe than if each cell in the grid corresponded to only one system.
(Update) Improving Local Connectivity
See this post for a simple technique to improve the local connectivity, which, as some have pointed out, is really too low with just the MST.
---
Alrighty, that took me a little too long to write, no surprises there, but you guys were patient to wait for it...so thank you
I will be getting back to my global economy work soon, but this multi-system work is also quite exciting, so I'm going to keep at it for a bit longer. I wanted to have a few more features like region names & system properties done for today, but I spent my time on the shortcut algorithm and the spatial faulting algorithm (which I cut from this devlog due to results not being that interesting) instead. Ah well! Perhaps next time
Hope you all have a great Friday!
AdamByrd wrote: ↑Fri Jul 20, 2018 12:50 pmFriends. Compatriots. Limit Theoreticians. I come bearing a dev log.
As always, I've been bouncing around like a madman. Sprinkling a little feature dust here, vacuuming a few bugs there, reinforcing scaffolding, ensuring the house stays tidy as we scale, etc etc. Oh, and I may have finished an entire engine system along the way. First up, Docking!
Docking
Last time I showed off the command interface. A large part of that was ensuring we can switch between 'contexts' smoothly. UI gets swapped out, the camera animates, bindings are changed out, and so on. These are small things that are going to be leveraged frequently. After finishing the command interface I wanted to continue working on gameplay and also push on these features a little more to see how they hold up. Docking seemed like a good fit.
We wanted to start with just the core mechanics: fly close to a space station, press a button, auto-pilot to the docking port, and see UI menus for everything you can do at that station.
First, a dockable component. The UI simply searches for dockables and if you're in range presents a button prompt to begin docking. The act of docking actually removes the player's ship from the world and adds it to the station instead. Similarly, once docked an undock prompt is presented.
I extended the MasterControl I implemented last time to add 'control sets'. The UI looks at the player each frame to determine which control set ought to be active and automatically switches to it. Previously we could choose from piloting, commanding, and debug controls. Now, when the player is docked we swap to a control set with things like your storage locker, merchants, and the jobs board. Since we can already swap out UI trees easily this ended up being dead simple to implement.
With all the state control in place, I wanted to make it a smooth, physical docking operation where you literally fly into the station. The AI is implemented through an action stack. Actions are pushed onto the stack and AI simply run their current action each frame, popping them once complete. Conveniently, the player is no different. The action stack is just empty and the UI controls poke the player's state directly. (This actually surprised me when I built the command interface because I could select my own ship along with my allies when giving orders and my own ship would fly along, taking part like any other unit.) I added a new docking action that is essentially the 'move to location' action that also happens to reparent the player from the system to the station once at the destination. And boom, with a whopping 7 lines of code you now auto-pilot right on in.
If a station is destroyed a fraction of the damage is inflicted on docked entities and they're released from the station. If your ship survives the damage, great, you can limp away. If not, well, your attacker gets to rummage through the debris of your ship along with the station.
It's not a particularly big or complicated feature, but I'm thoroughly pleased with how brain-dead easy it was to implement. The way Josh structured AI and actions is excellent. There's a ton of power and flexibility there with no real complexity. The whole of implementing docking took a day, with about 3 hours being the 'real work' and the rest polish and iteration.
Physics
We've been putting off physics work for a while now. We had kinematics, parenting, a naive broadphase, and sphere-vs-sphere narrowphase, and naive raycasting, but we still needed a lot more work. The broadphase failed spectacularly at large vs small object checking, raycasting needed to be accelerated through the broadphase spatial grid, and we wanted more shapes (convex hulls and boxes) and numerical robustness. We also didn't have a way to actually respond to collisions outside of kinematics (for sparks, sound effects, damage, etc). None of that is particularly scary, but the sheer amount of work still needed was.
Josh decided we should investigate off-the-shelf physics engines and decide which path would strike the right balance of development time and quality. So I took some time to evaluate our options. The 3 most well known being Havok, PhysX and Bullet. Honestly, I don't like the way most Havok demos look and feel. The licensing for PhysX is messy and I'm just kind of assuming it's a behemoth. In all the comparisons I've looked at Bullet seems to be the most consistent. It's rarely the absolute best in terms of performance or simulation quality, but it's very consistently #2 and right on the heels of #1. Physics and Havok on the other hand are excellent in some situations and abysmal in others. The consistency of Bullet is extremely appealing to me.
So I decided to integrate the bare minimum amount functionality leveraging Bullet that would let us see it in action. That would let us gauge the quality in our own use case and the time/difficulty associated with using it. I decided to do this as an entirely separate physics API in the engine that mirrored the existing one but didn't replace it. This let us actually toggle back and forth between new physics and old physics with a single variable. This was fantastic for comparing the two. We were able to ensure that everything felt exactly the same in both engines. This meant we wouldn't have to re-tune ship controls if we did end up swapping out the physics and also highlighted anywhere our current physics implementation was doing things incorrectly. Luckily, nearly everything matched up easily: drag, restitution, friction, etc. However, our inertia was pretty far from accurate. This worried me since it made ships feel completely different. In the end I was able to fix the inertia calculation in the old physics and updating the forces and torques could be done analytically to keep the same feel.
Once everything was set up correctly Bullet ended up feeling identical. Implementing it wasn't particularly difficult, it has all the features we want, and it's reasonably performant. It looked like it would be faster to switch to Bullet and we were confident it would yield very acceptable results. I set out to officially migrate us over and to flesh out the rest of the physics API we need to finish the game.
Unfortunately, nothing is ever easy and I it wasn't long before I started finding Bullet's rough edges, quirks, and flaws. Constraints are unusably slow, compound objects and triggers have awful API, I found a couple outright bugs, memory allocation is a mess, and the documentation is a half step above worthless.
Still, with enough hammering, it works. We have all the features we were aiming for and the implementation isn't a complete disaster. Some of the new stuff we now have is shapecasting, overlap tests, triggers, collision groups and masks, convex hulls and box shapes, and per-system physics. It may have taken 5 weeks, but it's done now and it shouldn't need any major changes going forward.
Overall, it's a win and I think it was the right choice. However, in the future I would likely avoid Bullet. In a professional setting I'd go with PhysX and see if it fares better. On hobby stuff I'd suck it up and write my own. The real kicker though, is that Bullet isn't awful. The author has done some quality work and I'm happy Bullet exists, it just the API design that's a disaster. All it needs is about a month of someone with API design chops hammering on it and it would go from irritating to a joy to use.
Math
Along the way, something happened that brings me great joy. I finally fixed all the math in the engine! This has been sitting in the back of my brain driving my nuts for months now. I probably first realized we had serious issues back in December. It's one of those things the tends to show up at unexpected times when you're in the middle of some other task and fixing it is going to break a ton of other things and you don't even know where it's broken and no one knows how quaternions even work and it's going to take forever and you just want to finish this one task and...you get the idea. It continually gets pushed to the back burner.
When I ran into it again with the camera work in the last update I told Josh that the next time it comes up one of us is going to suck it up and fix it. And by 'one of us' I mean me because Josh hates quaternion and matrix code.
Well, when I was integrating Bullet I ran right back into these math issues almost immediately. When rendering we have to get the position and rotation of objects out of the physics engine. Bullet has a lovely function that fills a matrix in an OpenGL format. But our matrices were in some weird, partially transposed state due to our bugs so we couldn't even use that matrix without first doing some obscene hacks to get it to match our format.
I mentally prepared myself for a good 5 days of anguish digging through our math and tracking down every last issue. I spent a couple hours cataloging all known issues and our coordinate system conventions in every part of the rendering pipeline. In the end, the majority of our issues traced back to Matrix_GetRight/Up/Forward and Quat_GetRight/Up/Forward. Turns out almost all of the math was 'correct' except when we converted from axes to actual on-screen directions. Both sets of functions were wrong and wrong in different ways. This is what made it tricky. Once I realized that I simplified a bunch of our math and found a few other small mistakes and remove all the ugly hacks we had before. The tests I wrote last time were a tremendous help. In the end, I only spent a day on it. Victory.
The End.
And now we get to the sad part. This will be my final dev log. My journey with the awesomeness that is Limit Theory is at an end.
From the very beginning Josh and I discussed a finite end. My job was to help clear the last major hurdles and open up the path for Josh to grind away on gameplay. To that end, I think this has been highly successful. The hope was that we'd be able to ship during that time frame, but alas, we didn't make it.
My plan for the last few years has been to move to the west coast, maybe Seattle, and find work with a stable indie studio. As luck would have it, something decided to fall directly into my lap. Shortly before GDC, Blizzard reached out to me and, long story short, I'm joining their new shared engine team at the beginning of August.
I leaned away from working for a AAA studio because I was scared of the potential soul-sucky nature of it, but once I actually visited Blizzard, that changed. I've gotta say, they've built an amazing culture there. Everyone I spoke with was happier and more creatively empowered than almost every indie studio I've seen. And I can bring Tess to work.
For the past month I've been working part time, winding down. I'm happy I managed to get Bullet fully integrated before I leave. I'm incredibly proud of the work I've done here, and extremely grateful I've gotten to work alongside an awesome programmer and person like Josh. I've grown tremendously as a programmer in my time here, and I certainly wouldn't be in the situation I am if it hadn't been for Procedural Reality. It's been a fantastic 14 months.
It's bittersweet, as endings tend to be. I'll miss the insanely creative and detailed discussions and the uniquely welcoming and cerebral community you've all built. I'm also excited beyond words about what comes next.
Cheers,
Adam
Statistics: Posted by Talvieno — Mon Jul 23, 2018 2:41 pm
CODE:
Gamma Centauri Ice Refinery - 50 ice/s + 100 water/s + 5 Talvienium/s Nuclear Reactor - 1 isotopes/s - 10 water/s + 100 energy cells/s Ballawhalla Prime - 50 water/s - 200 energy cells/s Ice Mining Barge 1 + 20 ice/s @ Ice Refinery Ice Mining Barge 2 + 20 ice/s @ Ice Refinery Water Trader 1 - 10 water/s @ Ice Refinery + 10 water/s @ Nuclear Reactor TOTAL - 10 ice/s + 40 water/s - 1 isotopes/s + 5 Talvienium/s - 100 energy cells/s
Statistics: Posted by JoshParnell — Wed Jun 13, 2018 10:25 am
Chris Martin wrote:Oh but if you never try, you'll never know
Just what you're worth
Statistics: Posted by JoshParnell — Tue May 22, 2018 5:09 pm
print(engineType)
just works. Structs visible to Lua are parsed, flattened, and sorted to put dependencies first. Commented code is ignored, preprocessor checks are evaluated, and warnings are emitted when preprocessor checks exist that may not match.PHX.TypeName.APIFunction()
. And there are hook points defined so that, when loading a set of API bindings, the game can inject additional functions into a 'namespace' and have them be indistinguishable from true engine API. Previously we had quite a few 'helper scripts' which contained functions the game needed but didn't quite belong in the engine. Trying to remember if Lerp is in PHX.Math or Math is...dumb.Directory_Close
and Directory_GetNext
have been mapped to object methods close
and getNext
while everything else was mapped to non-method functions. onDef_Directory
and onDef_Directory_t
are the hooks for extensions. Here's what those extensions look likerequireAll
and Namespaces. requireAll
is a straightforward way to load all scripts in a directory recursively and return a hierarchical table. Under the hood it's using the built in require
and package.path
which means it works completely seamlessly alongside normal Lua. Namespaces let us inject and optionally flatten those tables into the Lua global symbol table. No prefixing a bunch of code with PHX or Env. PHX.Vec3f(0, 1, 0)
gets simplified to Vec3f(0, 1, 0)
. But the PHX table still exists for disambiguating symbols when necessary. Previously we had manually written scripts that loaded every script in a directory (non-recursively) and returned a table. I especially enjoyed nuking those.CODE:
InputUpdateLayoutDraw
Statistics: Posted by AdamByrd — Sun May 13, 2018 10:00 am
Statistics: Posted by JoshParnell — Tue May 01, 2018 10:01 am
Statistics: Posted by JoshParnell — Fri Apr 20, 2018 1:35 pm
Statistics: Posted by JoshParnell — Mon Apr 09, 2018 10:11 am
Statistics: Posted by JoshParnell — Fri Mar 09, 2018 5:40 pm
Input.GetButtonPressed(Button.Space)
but it also stores the number of button transitions during the last update so it won't miss double presses or press and release in the same frame. It leverages SDLs ability to virtually map all controllers to a standard Xbox 360-like layout so just about any controller you plug in will Just Work. It ensures press and release events are perfectly paired (even if your controller is remapped while holding a button, much to Josh's annoyance) This API is extremely robust and basically complete. Everything LT related has been migrated over. It needs slight improvements to the way modifiers are handled, haptic feedback support, and to be tested with HOTAS / unmapped controllers.Statistics: Posted by AdamByrd — Fri Feb 16, 2018 10:32 am
LindseyReid wrote: ↑Thu Jan 18, 2018 3:47 pmLimit Theory @ PAX South 2018 Recap
Hey everyone! If you didn't know already, we spent last weekend at PAX South showing off a Limit Theory demo at a booth on the expo floor. Since many of you couldn't make it, this post will recap what was in the demo and how PAX went. There are a few goofy developer photos and a demo video for you to enjoy
Here's a 3-minute clip of us playing with the demo! (there's no sound on purpose )
iframe
What Was In the Demo
The demo had two parts:
1, a small slice of combat in the form of a dogfighter, and
2, a small demo of the ship customizer.
At first, we designed the combat to have a goal, with the player needing to dodge bullets to retain health and earn credits from kills in order to buy ship upgrades. However, after just a few hours at PAX, we decided that making the player invulnerable and removing the goals was WAY more fun. Our idea of how big the demo needed to be for PAX was overestimated; people would drop by for a couple of minutes and really just want to fly around and shoot stuff. Dying wasn't so fun, and earning credits to upgrade parts was definitely out of the scope of what a short demo needed.
So, what we ended up with was a super simple dogfighter! The player had a certain amount of friendlies and an equal amount of enemies that would constantly respawn, and there was no final goal. Players could fly around and shoot the enemies, with a couple extra fun controls: pushing down the right stick would allow the player to spawn new friendlies and enemies, and the up and down buttons on the D-Pad allowed controlling friendlies. Up would tell the friendlies to go kill whatever enemy the player was locked on to, then return to the player; down would tell friendlies to find any random target, kill it, and then return to the player. Friendlies spawned with the right stick would follow the player in sphereical formation.
In addition, the game had a small ship customizer demo. The customizer allowed you to pick from the three fighter classes I've written so far (surreal, classic, and tie-like) and customize the shape and size of the wings and hull of the ship, as well as a couple of details like the surface detailing and overall warps. The full version will allow you to do much more, but this demo was in the small scope of what people would play with during their short stop at our PAX booth. Josh also added the ability to randomize a color pattern on the ship, which was cool and well-received.
How It Went
In short: really well! We had a constant stream of visitors to the booth with almost no downtime, and virtually everybody who played enjoyed it. We ran out of the 300 business cards we printed. People really enjoyed the dogfighting, and while fewer people used the ship customizer, those that did deeply enjoyed it and said things like "I could play with this all day!"
Josh made small tweaks to the code throughout PAX, sometimes to implement or change a feature (like when we made players invulnerable), to fix a small bug (of which we had very few), or to make a change a player asked for. One of our biggest requests, for example, was to make the control axes inverted, which we're certainly going to take note of.
Players also had a TON of fun with the 'spawn' button. We had several groups of people attempt to spawn as many NPCs as they could, with the goal of crashing the game. (Un?)fortunately, the game didn't crash from excessive NPC spawning, even when we had 10,000+ ships on screen. It did, however, start to slow down the framerate... after around 2000 ships. Thousands of ships flying in various formations, hundreds-of-thousands of pulse lasers, and all of it rendered with 2x supersampling (meaning rendered @ 4K and downsampled to 1080p) -- our work on performance optimization seems to have paid off. Players frequently expressed surprise at how smooth the game ran despite having loads of stuff going on
Here's one group of players who spawned 4000+ ships, with Josh smiling in the back, probably at our performance:Spoiler: SHOW
And here's Josh deep in the code, looking super exstatic about me (Lindsey) taking a coding selfie with him:Spoiler: SHOW
Fin
Overall, PAX was a great experience for us, both in marketing and for testing the game. We made real connections with fans old and new, from backers, to people who had heard about the game a couple of years ago, to people who were learning about it for the first time. The demo was also great test of our workflow for writing gameplay code and of our performance. We found a few things to clean up with regards to architecture that Josh and Adam are now working on. We're very, very close to going full-force on gameplay code, and the PAX demo was a great milestone for that.
Here are a couple of photos of the team in front of our booth.
Josh (left), Lindsey (middle), Adam (right):Spoiler: SHOW
Lindsey (left), Josh (middle), Adam (right):Spoiler: SHOW
That's all, folks! I hope this has satiated your curiosity about what went on at PAX. Here's the link to the demo video again. Feel free to ask more questions about what was in the demo and such, and thank you always for your continued support.
- The LT Team
JoshParnell wrote: ↑Thu Jan 18, 2018 5:37 pmThursday, January 18, 2018
Greets everyone and Happy New Years / Merry Christmas (a bit late)! I had, as usual, intended to post before now, but the time since my last log has been absolutely jam-packed with pumping out work for our PAX Demo. Now that it's over, I'm excited to come back and add my own thoughts on how it went, as well as update you all on the progress that's been made leading up the the release.
Of course, I recommend reading the official PAX recap posted by Lindsey earlier today for a general overview of the event.
Progress Since Last Time...
It's going to be difficult for me to remember everything. It's rather scary how quickly we're able to implement vast swaths of functionality now that we're sitting pretty with respect to our supporting engine & lower-level systems! You'll have to excuse the wall-of-bullet points and the scatterbrained parenthetical thoughts accompanying them.
- Added working pulse laser turrets, muzzle flashes, thrusters with engine trails, explosions, and several other effects (some ported from LTC++, some brand-new)
- Ported & improved AI architecture from LTC++; implemented escort, formation flying, dogfighting, and a few other AI actions
- Added AI squad management & hierarchical formation (WIP -- currently the squad disbands into individual units if the leader is destroyed, although this was actually a neat feature for the demo)
- Added ownership and asset tracking; all relevant objects now belong to an ownership hierarchy (in the demo, assets are owned by either the human player or an AI player who is controlling the actions of enemy squads)
- Added thruster overloading ('boosting'); added AI ability to use boost (still need to generalize to all ship hardpoints to have generic 'hardpoint overclocking')
- Added energy grid / capacitor component for 'real' energy mechanics (like in LTP); note that we had infinite energy enabled in the demo for fun (hence why the left capacitor bar never depletes when firing or boosting)
- Added basic manufacturing component; the home base station in the demo is actually capable of manufacturing ships using a build queue and pseudo-blueprints, although we ended up not using this functionality due to reasons given by Lindsey in the recap (complex game mechanics ended up being less approachable for a play-for-a-few-minutes demo)
- Added basic HUD with working soft and hard target locking, forward reticles ('lead indicators'), capacitor and health meters, and optional auto-targetting (turned off for most of the demo)
- Added disposition tracking to allow dynamic inter-person / inter-faction relations (the enemies in the demo are shown as enemies not because they are in any special 'enemy' list, but because the human player and the AI player controlling them are set to have maximally-hostile standing with one other)
- Enabled & extended a proof-of-concept paint shader on metal assets to allow per-ship/per-station coloring
- Added dust clouds (still need work to be more subtle at high velocities -- a problem numerous people pointed out in LTC++ ); improved dust flecks to be more subtle
- Added several post-processing effects for use with alternative view modes like the ship editor / slow-time action camera
- Added velocity-dependent radial blur (currently a bit too aggressive?)
- Major optimizations to rendering architecture, especially with respect to supersampling -- we ran the demo at 100+ FPS with 2x supersampling on my laptop
- Made everything work on gamepads + improved engine-level support for joysticks, gamepads, HOTAS, etc.
- Partially-implemented an active deflector shield (for fun) that reflects energy weapons -- didn't finish in time for PAX, but may keep the idea of an 'active' shield mechanic on top of passive shields
- Improved chase camera dynamics for more 'classic Freelancer' feeling (still perfecting it, but we're definitely getting somewhere!)
Indeed, quite a lot of quality functionality came about thanks to our PAX sprint! Note, in particular, how this list, in contrast to so many of my recent lists, is very much brimming with gameplay and immediately-related-to-gameplay features
Takeaways from PAX
Naturally there was a lot to be gleaned from publicly demoing a slice of the game for the first time since last year, but I think, if I had to put my finger on something concrete (other than just 'people are really going to enjoy this labor of love'), it would be the comfort with which I walked away from the experience. Comfort that the tireless, seemingly-never-ending Royal Crusade Against the Excessive Usage of Milliseconds (aka 'performance optimization') has genuinely paid off. Perhaps even more broadly, comfort that the unspeakable hours that have been put into solving FPLT ever since the fall of LTC++ have truly been worth the pain that they all-to-frequently caused.
If I were to boot up the old LTC++ and try to push it to do what our current setup did at the PAX, it would have been a spectacular display of tears and molten lava -- the former pouring from me, the latter pouring from my laptop. We are easily pushing 10x the amount of activity with extremely high, consistent framerate. We can push 100x the activity almost as easily, although there are a few choice places to which I must make small tweaks before 1000+ ship battles will be as buttery-smooth as the 100+ battles are currently. All the while, we're not only putting more entities in the world, but the amount of dynamism is starkly superior to LTC++. That demo is running full collision on all entities -- NPC ships collide with one another and with every asteroid in the scene; ramming small asteroids sends them flying off into the abyss; slowly pushing a large asteroid is even feasible with a large enough fleet. The AI is driving thousands of turrets accross hundreds of ships, each computing viable firing solutions. Friendly-fire is turned off for the demo, but projectiles still collide with everything in the scene. The collision is still slightly coarse (you will 'bounce' off of asteroids slightly sooner than expected), but this will be remedied with the help of Adam's InsaneBSPs. All those little details add up quickly into an experience that feels genuine, deep, and rich with opportunity.
All-in-all, what we have going on is exactly what LT promised to provide, and what I've thrashed my neurons for so many years to make possible: a universe alive with activity. In the demo, that activity is a bit boring, what with the AI only thinking about shooting things. But imagine the same scale of activity applied to a diversity of gameplay mechanics -- trading, exploring, mining, patrolling, constructing, researching, so on and so forth -- and you are left with the vision of a vibrant, living universe that captured the enthusiasm of so many (including myself) at the outset of LT. A single player experience in which you are far from alone
Working on the demo reinvigorated me in so many ways. Seeing even the simplest of gameplay mechanics come together to create moments of fun; having new gameplay ideas that required only an hour or two to bring to life; falling back in love with writing AI...it was all very therapeutic
The icing on the cake, of course, was player response. As mentioned by Lindsey in the PAX recap, we had numerous players express their amazement at the sheer amount of 'stuff' going on (especially those who spawned hundreds/thousands of AI escorts, expecting a crash but instead finding only a very gradual FPS degradation). We received plenty of compliments about the beautiful visual style, the smooth and responsive feeling of it all, the joy of being able to issue orders to a fleet, the quality of the procedural assets (Lindsey's ship generator amazed more than a few people, especially once she had made clear that the ships were procedural down to the very vertex, not simply lego-style recombinations of prefab assets). Even with such a small taste of the full Limit Theory experience, people responded really positively. Yet again, it brings me comfort and excitement -- for if just a tiny morsel of the cake is enjoyable, surely the full experience that awaits you all at launch will satisfy
Going Forward
The sprint to PAX functionality gave us a chance to see how our various systems and architectures performed not just with respect to runtime, but with respect to developer time -- the second half of FPLT is, after all, making this raw engine power easy to harness and sculpt into something that matters. For the most part, I'd say we succeeded there as well. However, as was to be expected, pushing content into the demo in such a short time gave us critical insights into where things are too complex or less-than-intuitive.
Adam and I are going to spend the rest of the month doing a sort of PAX-postmortem, taking some time while we have it to deal with those hitches that affected our PAX demo development efficiency (and will, by extension, impact our dev efficiency going forward toward release.)
On my side, perhaps the biggest challenge remaining is moving our PAX demo into mod format. As you may recall from my last log, the mod format was well-underway at the time. As it stands today, it's more-or-less complete, but yet again, moving over representative gameplay snippets like some of those developed for the demo will reveal the true efficacy of a system that looks fantastic on paper.
I'm really looking forward to the next few weeks, as I think it's going to continue to be a lot of fun writing new gameplay, listening closely to see what the code is telling us about our architecture, and iterating until we're doing bigger and bigger things with less and less effort. The PAX demo marked the true start of the ramp-up into gameplay code. The rest of the month will be an outward spiral of ramp-up and ramping-up the ramp-up (you know, d2G/dt2, where G(t) is gameplay ).
Thanks for listening
I put together a small album of some of the screenshots I took during PAX (and a few after). Mostly of people doing absurd things :V Please note that the radial blur & horizontal screen effects were just a little PAX polish for making the camera modes look distinct. LT does not have the outer portion of the screen blurred out most of the time
Limit Theory Devlog Gallery ~ January 18, 2018
Statistics: Posted by Talvieno — Sat Jan 20, 2018 2:19 pm
Statistics: Posted by LindseyReid — Thu Jan 11, 2018 9:49 am
If you'd like to log in and post suggestions for what they can include in the demo, Josh posted a Limit Theory PAX Demo 2018 Suggestions Thread.JoshParnell wrote: ↑Wed Dec 20, 2017 12:57 pmLimit Theory @ PAX South 2018
Hey everyone!
I'm going to be hopping on the devlog train in a moment here, but before I do, I want to get this information out ASAP so that anyone interested can make arrangements sooner rather than later. And the big news is...already spoiled by the title of this post!
We'll be demoing LT again at PAX South this year! When I say we, I mean all three of us from the office here will be going, so if you'd like to praise Adam for his stupidly-fast BSPs, or Lindsey for her stupidly-fast progress on great-looking ships, or me on my stupidly-lackluster ability to meet deadlines ...you can do any or all of the above!
PAX South will be held in San Antonio, TX and will run from Friday, January 12 to Sunday, January 14. We'll be there with an LT demo all three days, although at the moment, it appears that we may be closing up early on Sunday. I'm waiting for some clarification from the Tech Park on our Sunday schedule, and will update this post & thread as soon as I know for sure. So, if you're interested/able to come, pick whichever is most convenient for you, but don't bank on us being around after ~12ish on Sunday. The cost is $40 USD for a one-day pass. Unfortunately, it appears that the three-day passes are already sold out.
Official PAX South Site Links:
Registration & Purchasing a Pass
Full Schedule
As with last year, we're going as a group with the Louisiana Tech Park, so to find us you should look for some kind of signage related to "Louisiana Tech Park," "Baton Rouge Game Developers," or possibly "New Orleans Game Developers"...and of course, we will have a smaller sign with "Limit Theory" on it. Our setup will likely be a mounted HD TV with a gamepad, since we'll be pressed for space.
The Demo
As of this week we've started planning out and sprinting on features for the LT PAX demo. Naturally, since LT isn't ready to play yet (nor would the full game make for a compelling five-minute demo experience), our demo will aim to give 'a taste' of Limit Theory in a format that's more amenable to picking up a gamepad for a few minutes and having some fun. It will be unequivocally superior to last year's "war of the box 'ships' demo."
If all goes according to plan, we'll be showing off a combat demo wherein you must defend against progressively-more-difficult waves of attacking ships. Successful defense rewards the player with credits that can be used to purchase upgrades to weaponry, consumable items, full-ship upgrades, new AI teammates, and possibly more All of this will, of course, be happening in procedurally-generated systems with procedural asteroid fields, planets, nebulae, and (possibly) stations (although they may be of the 'old' variety since Lindsey is focused on ships at the moment).
Additionally, since Lindsey has made great progress with ships, we'll be integrating a 'ship generator UI' that allows for customization of the generating parameters, so that you can play around with customizing your ship and seeing the PCG work in real-time! She's got some great ideas concerning how we might even save the best user-generated ships so that they continue to pop up throughout the day (you may come back to find someone piloting or fighting a ship that you custom-generated!)
If you've got reasonable ideas/feature requests for the demo that you think would be fun for people to see, please post in the official LT PAX Demo Suggestions thread, but please read the first post before doing so!
If you're able to make it, then we look forward to meeting you! Otherwise, fret not, for there will surely be an abundance of shinies from the ordeal, including an endless fountain of screenies, some real-life pictures so you can see just how photogenic we programmers are, and hopefully some video capture of user play sessions.
Statistics: Posted by Talvieno — Fri Dec 29, 2017 8:41 am
So, I have good news and bad news! The bad news is that I was out sick much of last week with a nasty post-holiday-cold, so I wasn't super productive then. The good news is that I was able to bounce back this week with MAJOR breakthroughs on ships!!!LindseyReid wrote: ↑Fri Dec 01, 2017 7:41 pmMy plan moving forward is quite exciting: between now and the new year, I want to jam on generating a complete bomber-sized ship.
Statistics: Posted by LindseyReid — Fri Dec 15, 2017 6:26 pm
Statistics: Posted by Talvieno — Mon Dec 04, 2017 7:24 pm
CODE:
other code other code other code other other other ... <-- I am here :'[ --> ... ...
CODE:
my code my code my code ... <-- yield; everyone ELSE is here >:] --> ... mine mine mine mine mine
Statistics: Posted by JoshParnell — Tue Nov 07, 2017 9:47 am
Statistics: Posted by LindseyReid — Mon Oct 30, 2017 9:28 am
Statistics: Posted by JoshParnell — Tue Oct 24, 2017 3:05 pm
Statistics: Posted by JoshParnell — Thu Oct 05, 2017 6:53 pm
Link to original: viewtopic.php?f=30&t=6310AdamByrd wrote: ↑Mon Oct 02, 2017 11:31 amHey guys. I'm going to try something new for a bit and see how it goes. In between Josh's bigger updates I'm going to start posting smaller updates. These mini-updates will focus on the specific problem I'm solving at the moment. The goal is to go deeper into detail than the bigger updates normally do and is often going to be centered around code architecture since I've been spending a lot of time there lately. They will also be more informal: I'm going to write them without much revision and without the flair that generally comes with Josh's writing. This is mostly just laziness that I'm selling as time savings and pragmatism. I also imagine this being a little more interactive than the usual updates, so feel free to ask specific questions or tell me what you'd like to hear more about and I'll do my best. Off topic stuff is fine as well as I realize you guys don't know a whole lot about me yet. What I won't be covering is what Josh is currently working on. For one I don't want to steal his thunder and two I want to ensure there's still new information in the regular updates. Onward!
Recap
First a bit of history. My primary goal since teaming up with Josh has been to get to gameplay as soon as possible. In a particularly productive team meeting early on this lead to the birth of Lil'T. The original goal was to have a single, playable system in a week. Something basic with player controls, a nebula, and some asteroids. This was back when I had just finished the BSP implementation. We had been working solely in the engine and didn't even have a separate (code) project for LT. I didn't know any LUA or how to start writing gameplay that leveraged the engine so this was a good motivator to start knocking down those barriers. I think it ended up being about 2 weeks before we really got to the point we wanted to be. I have to say, hooking up the BSPs for the first time and being able to click things in the scene felt really damn good.
Now, as much as I want to get to gameplay, the second major goal is making sure the code we write is shippable. It can't be prototype stuff that's going to need to be re-written. It doesn't have to 100% perfect and complete either, but it needs to be written in a way that can expanded without needing to be refactored. In getting the first phase of Lil'T running it became obvious that the infrastructure to support LUA needed to be in before going further. That took another few weeks and you've likely read about some of that in the past couple of updates. During that work we spent a lot of time profiling, testing, and tweaking things and it became pretty obvious that being able to do some of that while the game was running would save us a bunch of time so I set to task on the debug UI.
With the dev UI in a good spot we're shifting back to gameplay again. We're likely going to do this 1-2 combo of sprinting on gameplay for a bit then stepping back to improve the infrastructure supporting it a few more times. Often we can't really tell what the scaffolding needs to look like until we have concrete gameplay as a guide. We spent a couple of days talking through how we wanted to simulate entities. Since they have one-to-many parent-child relationships (a ship is the parent of it's turrets), the game objects form a tree structure. We compared hierarchical updates using depth first and breadth first traversal. We compared job-based (run on all entities) and event-based (build a list of entities that need to be updated). Ultimately we settled on event-based updates with the ability to create jobs within that framework.
Input vs Simulation
Once we nailed down how we wanted updates to be processed, input became the next target. We ended up with a lot of code that looks like this:(Note that I'm being loose with the term 'update' in the text (but not the code). The core game loop is essentially simulate, update, draw. Simulate is the fixed interval simulation step. Update happens right before draw and is for things like animation and interpolation. Draw is for, well, drawing. Also note that handling input in the update step is wrong and will be changed eventually. We aren't currently buffering input and since the simulation rate is much lower than the update rate we miss a lot of input when handling it in update at the moment.)CODE:
function onUpdate (dt, hasFocus) if hasFocus then if PHX.Mouse.Pressed(PHX.MouseButton.Left) then self:fire() end if PHX.Mouse.Pressed(PHX.MouseButton.Right) then self.camera:setTarget(self:getPick()) end endend
This isn't great. Having to manually track, pass, and handle focus in every single location that processes input is going to lead to a lot of mistakes and unnecessarily obtuse code flow. We knew this wasn't going to last long as it was being written and it needed to be addressed soon, before enough incorrect code built up that refactoring it would be a big task.
Josh and I talked through this quite a bit and his idea was to treat the game window as a fairly standard UI. The GameView would just be a UI widget that displays the final, rendered view of the simulation. The simulation becomes an autonomous thing that marches through time, updating its own state without any concept of a camera, a player, or input. UI widgets will provide visible controls and input handling that inform the simulation of requested state changes. The GameView decides how it should render the view of the simulation.
It took me a bit of time to understand the implications of this approach. It sounded a bit odd at first, but the more I worked through it, the more I was able to see the large number of subtle benefits.There's probably a lot more nuance that I'm leaving out. Anyway, we're currently using the dev UI to handle this. We didn't originally intend for the dev UI to be the final UI system but the performance is good enough that it's actually a possibility. It's powerful and easy to use. However, if the dev UI is swapped out in the future it's not going to affect the way the gameplay code is written so it's natural to move forward with it for now.
- The GameView gets the full benefit of the automatic layout functionality of the UI. Debug and gameplay UI elements can push the GameView out of the way in addition to just overlapping it. If you've noticed how the debug UI overlaps gameplay that's actually quite annoying. It's nicer if the debug window is able to make the gameplay view narrower and slide it to the right so they are side by side instead. In general it means we can allow the game view to be resized, moved, snapped, etc very easily and naturally. We can iterate on UI layout faster, allow players to customize their UI easily, and handle window resizes without any added work.
- Multiple GameViews can exist (think radar, scanning, minimap, whole-system views, etc).
- Input focus is already handled cleanly. The UI tracks what your mouse is over, which widget has focus, is being dragged, etc. It's trivial to extend this to have separate mouse and keyboard focus, hard and soft focus, separate onInput functions for letting only the focused widget handle input, and whatever else might be needed.
- The amount of branching in gameplay code drops significantly. We don't have to check for focus or input because that gets hoisted to the highest level and doesn't need to be repeated all over the place. Even with our tiny system, the amount of code and complexity immediately dropped.
- The simulation takes on more of a client-server model. Input is handled in the 'client' which then requests state changes on the 'server'. Validation in the simulation all happens in one place. We end up being forced to build a clean API in some sense.
- Concepts like control schemes become much easier to think about and implement. Since each form of input is going to be a separate UI widget completely changing how the game controls just means creating a new widget and adding it to the UI hierarchy.
Of course, making this change meant a decent amount of refactoring. I had to pull all of our input handling out, decide where it went and reimplement it in the new system. I ended up with 3 new widgets: GameView, DebugWindow, and DebugPicker. I also reimplemented the data inspectors Josh added a while back so we can actually walk through the entire game state from UI windows. I also took the time to add a bit more UI polish: added stretch weights to grid columns/rows, fixed subtle positioning errors in labels, added alignment to labels.
This is mostly under-the-hood work, but I figure I can at least drop a gif of the GameView being animated smoothly: https://i.imgur.com/EkASTsN.mp4
This update is a bit higher level than I'm aiming for in general, but it's not a very involved or probably interesting topic and it's only a few days worth of work. Let me know what you guys want to hear more/less about so I know where to focus in the future posts.
Cheers
Statistics: Posted by Talvieno — Mon Oct 02, 2017 7:43 pm
Statistics: Posted by JoshParnell — Sun Sep 03, 2017 7:55 am
Statistics: Posted by JoshParnell — Sun Aug 20, 2017 9:57 am
AdamByrd wrote: ↑Tue Aug 15, 2017 9:59 amGuys! Gals! Hey. I'm just popping on to check in with a super ultra tiny mini update.
Things are starting to move fast. Lil'T is alive and kicking. And producing pixels. Actual pixels! (Seriously, I've spent so much time staring at text books and data dumps these last three months I almost forgot we're making a game. With nebulas and rocks and space pirates.) I've been working to nail down how we're going to be writing actual gameplay code. That means fleshing out how Lua talks to C to keep heavy bits and allocations in fast code land, how to make that Lua feel 'normal' and not like C grafted onto Lua (metatables are really nice!), making sure LuaJIT actually jits to assembly, iterating on the engine API to remove friction, and building a prototype solar system. I'm insanely excited about the progress we've been making. All the mountainous unknowns are now small piles of exploded rubble. We're moving faster by the day.
The GIF floodgates are opening soon, my friends.
What a time to be alive.
Statistics: Posted by Talvieno — Wed Aug 16, 2017 9:59 am
Statistics: Posted by JoshParnell — Sun Jul 30, 2017 2:29 pm
Statistics: Posted by JoshParnell — Tue Jul 25, 2017 8:36 am
Statistics: Posted by JoshParnell — Wed Jun 28, 2017 12:18 pm
Statistics: Posted by JoshParnell — Mon Jun 12, 2017 8:33 pm
Statistics: Posted by JoshParnell — Sun Jun 04, 2017 8:19 am
Statistics: Posted by JoshParnell — Fri May 26, 2017 7:22 am
Statistics: Posted by JoshParnell — Tue May 16, 2017 1:56 pm
Statistics: Posted by JoshParnell — Fri May 05, 2017 4:32 pm
And there you have it. Kinematics and a few other pieces of physics-related information, along with graphical information, live in C. The rest (requiring no per-frame updating) lives in Lua. Components are Lua-side. So really, it's just an ES that lives in C...an Entity System without the components, since I decided these are, in the 90% of cases, lightweight enough to be handled by Lua without issue. And so it will be until something starts causing major issues.Boss : "Build me that ECS."
Josh : "Aye sir."
< 1 week passes. >
Boss : "Where's my ECS."
Josh : "Working on it."
Boss : "Get it done kid."
< 1 week passes. >
Boss : "Where's my ECS."
Josh : "I have a lot of good designs."
Boss : "Neat. So where's my ECS."
Josh : "Well sir, currently none of them can elegantly accommodate the fact that thrusters have a key part of their rendering behavior tied to one little piece of state that should, in earnest, live on the Lua side, as it's really not 'intrinsic' to anything. Sadly, in the case of thrusters, there are enough of them that the data martialling will become problematic and result in framerate loss. On the other hand, it's difficult to see where this state should live on the C side of the system."
Boss : "...that right? So...just...thrusters..."
Josh : "Well sir the general problem is likely to crop up in a few other pla--"
< Boss raises hand so as to silence Josh. >
Boss : "It's all so...incredible. So fascinating. But see here, look Josh, let me ask you just this one thing."
Josh : "...yes sir?"
Boss : "WHERE. IS. MY. <expletives censored> ENTITY COMPONENT SYSTEM?"
Josh : *Quickly hands over imperfect but functional system*
< Boss storms away angrily. Cornelius Evazan enters from stage left. >
Cornelius : "You just watch yourself."
Josh : "I'll be careful."
Cornelius : "You'll be dead!"
CODE:
return { id = '_LTBE_SYSTEM', name = 'Limit Theory Base Entities: System', desc = 'Defines the System Entity', author = 'Josh', version = 0.01, content = { { type = 'Entity', id = 'System', components = { 'CollisionDetector', 'EntityContainer', 'NaturalResources', 'Zones', }, }, { type = 'Listener', id = 'System.onCreate', fn = function (Game, e, seed) print('Looky, a system!') local rng = RNG.Create(seed) e.name = 'Omicron ' .. tostring(rng:getInt(10, 20)) e.starDir = rng:getDirection3() e.starColor = rng:getVec3(0.5, 1.0) -- Populate the system with...you know...lots of stuff end, }, { type = 'Listener', id = 'Engine.onInit', fn = function (Game) local seed = 1337 local system = Game:createEntity('System', seed) -- TODO: Implement Limit Theory end, }, }}
Statistics: Posted by JoshParnell — Sun Apr 23, 2017 9:50 pm
Statistics: Posted by JoshParnell — Thu Apr 13, 2017 8:57 pm
CODE:
/* Basic Mining AI Pseudocode. */start: self.clearActions() targets = self.getSystem().getEntitiesWithComponent(Component.Harvestable) miningTarget = argMax over target in targets of target.getInventoryUsed() / self.getTravelTime(target) self.pushAction(TravelToObject(miningTarget), align)align: /* Align myself 'tangent'-ish to the target. We could get way fancier here, taking into account turret line-of-sight. Quick version is to just assume being tangent will yield goood LOS for all. */ toSurface = miningTarget.getNearestSurfacePoint(self.getPos()) - self.getPos() self.pushAction(AlignAxisYTo(toSurface), harvest)harvest: /* TODO: Maybe move around the target a bit so as to be less...boring? */ /* TODO: Fire each turret at a different (visible) surface point. */ for turret in self.getTurrets() if turret.getType() == TurretType.TransferUnit turret.fireAt(miningTarget) self.notify(InventoryFull(self), full) self.notify(InventoryEmpty(miningTarget), start) self.notify(NotInRange(self, miningTarget), reposition)full: self.pushAction(DockAt(dropoff), unload)reposition: /* Calculate a point near the surface of the target such that all transfer units are in range but I'm still a safe distance away */ self.pushAction(TravelToPoint(point), align)unload: self.transferInventory(dropoff, ItemType.RawMaterial) self.pushAction(Undock(), start)
Statistics: Posted by JoshParnell — Mon Apr 03, 2017 9:47 pm
Statistics: Posted by JoshParnell — Sun Mar 26, 2017 8:22 pm
Statistics: Posted by JoshParnell — Fri Mar 17, 2017 12:17 pm
Statistics: Posted by JoshParnell — Wed Mar 08, 2017 8:08 pm
Statistics: Posted by JoshParnell — Wed Mar 01, 2017 9:45 am
Statistics: Posted by JoshParnell — Tue Feb 21, 2017 9:49 pm
Statistics: Posted by JoshParnell — Sun Feb 12, 2017 6:33 pm
Statistics: Posted by JoshParnell — Mon Feb 06, 2017 12:14 pm
Statistics: Posted by Talvieno — Thu Feb 02, 2017 4:57 pm
Statistics: Posted by JoshParnell — Wed Jan 25, 2017 4:35 pm
<3 JoshQ. Thanks for joining us Josh.
A. Thanks for having me, imaginary forum member. What can I answer for you?
Q. Well, I read your post. I honestly did. But all I really heard was 'code code code C++ Python code Lua code JIT beep boop mainframe.' So...what's going on with Limit Theory, you know, that GAME that I'd like to be playing right now?
A. Yeah...it frustrates me too. I don't enjoy working on the technical side of it all nearly as much as I used to; frankly I would much rather be tying off loose ends on the AI, zone control mechanics, simulation LODing, unstable wormholes mechanics, etc. But, as I explained, this problem must be solved before I can finish LT, and I would rather throw myself entirely into solving it than split my time between solving it and trying to write gameplay code when the platform for said code isn't yet a solved problem.
Q. So it sounds like you've made no gameplay progress then.
A. Not true, but it is true that I haven't made nearly as much gameplay progress as you would want from two years of work (see above: >95% effort dedicated to the big problem).
Q. Oh? So then, what part of the game has changed the most since we last saw it?
A. AI has progressed quite dramatically. The top-level AI action ('Action_PlayGame', heh) is much more fleshed-out than before, meaning AI players are capable of literally 'playing' Limit Theory to a greater capacity than before. There are still missing elements, mostly because of missing logic for actions that deal with higher-level concepts like war, research, and construction. There's still a good bit to do here, but, having written some AI now in both Python and Lua, I've gotta say that, if we can get a fast scripting solution to work, AI development is going to go much faster when resumed full-time!
Q. Cool. You mentioned some stuff in the post that kind of scared me and made me think you're basically re-writing LT. Is that the case?
A. Definitely not. I'm changing the foundation on which LT rests, but by no means have I torn down the building. As stated above, the 'core' pieces of LT, i.e., much of the actual 'engine,' is still present in the C library. GPU code is all present and doesn't require porting. As for gameplay code / stuff that used to be in LTSL, I've ported it enough times now to know that it's a quick task. I've said it before and I'll say it again: it's the ideas beneath the code that the majority of the time to come up with. Typing code is easy. Coming up with an idea that will make the code do something wonderful isn't. Very little is 'lost' in this process.
Q. Hrmmm....so then, you've got it rendering and such?
A. Yep, I've got it rendering under both the current attack vector (LuaJIT) and the older one (Python). It's not really a big task with the library in place.
Q. Sweet, so, screenies?
A. Don't...even...!
Q. But I... :3
A. It looks the same as what you've already seen. I haven't worked on graphics! Seriously, the graphics monkey is in the cage. Gameplay, yes. FPLT, very yes. Graphics, no. I literally haven't changed the LT graphics in two years. It's been hard for me to control myself like that, but yes, I'm ready to accept that the current graphics are absolutely good enough for release. LT 1.0 is going to look very much like the latest screenshots you've seen, except with the missing content filled in. No more 'new metal shader version 298.0'.
Q. Fair enough. I'm glad you managed to control the monkey. Speaking of monkies, when beta?
A. When I solve FPLT and steamroll the remaining gameplay content.
Q. Ugh. I hate this 'FPLT' thing. You know, now that I think about it, what if you just ... ? Wouldn't that work?
A. (Depending on nature of ...): No, sorry. / It's a good idea but I've tried it and it didn't work out. / Well, that's essentially what I'm trying to do. / Dear God, why didn't I think of that, you're a genius, FPLT IS SOLVE \o/ *hands over bank account while weeping tears of joy*
Q. Okay then...back on-topic, why did you desert the forums?
A. I honestly didn't mean for it to become a 'thing.' It snowballed out of control: I just wasn't on the forums for a while, not for any particular reason, and then one day it was like a 'Josh is gone' thing, at which point I could have chosen to say "No I'm not," which would have pretty much done the trick. But instead I chose to give in to anxiety and was all "oh no, I'm gone!? Well now I have to come back with fireworks! " I really regret making that decision and letting it stagnate for so long.
Q. You should, a lot of us pretty much lost faith in you.
A. I understand. To be honest I can't say that I deserve more. All I would ask is that you give LT the benefit of the doubt in the sense that when it comes out, judge it as Limit Theory the game, not as Limit Theory the product of a guy who let you down.
Q. We'll see. What about Kickstarter though? I mean it's been even longer in the dark for them...
A. It's been a general pattern throughout development that I post more frequently to the forums than to KS. Historically, I've only put up KS posts when I felt that I had 'very substantial' material to post. As per above with the whole 'not a glamorous era in development,' I felt that I'd be letting everyone down with a text-based post, even if it's the best way to bring everyone up to speed. Once again, a regrettable choice made by Showman Josh, but now attempting to be set right by Pragmatic Josh.
Q. I like the sound of this 'pragmatic' Josh guy. Maybe he can finally get us a game?
A. Yes.
Q. Again, we'll see. I'm almost ready to dip my toes back into the water, but the truth is, you seem pretty good with words, yet have let us down quite a few times with those words.
A. Which is exactly why I've not sugarcoated this situation. Did you get the same 'thrill' reading all this that you did when I released an update video? Most assuredly not. But what I'm good at is raw honesty, which sometimes makes it hard for me when I honestly believe in my capability to do things at which I end up failing, or when the situation is honestly not so great. But I think you all, at this point, would much rather hear not-so-fun truths than nothing at all, which are the only two choices I've got. Notice the lack of glitter, unicorns, and grandiose promises in this whole thing!
Q. I certainly noticed the lack of glitter. Speaking of which, why on earth did you not provide a TL;DR for what may be your most obnoxious wall of text ever?
A. I considered it. I even wrote a TL;DR. But I realized very quickly that doing so was completely counter-productive to the point of this whole post. I took a lot of time to try to explain the current state of Limit Theory development; to try to get everyone to understand precisely what I'm doing from day-to-day right now and why it's necessary. If someone truly wants to understand it, they need to read this post. If not, then 'LT is not kill' should suffice. I can't explain it all and make my explanation super-compact. I could do that back when everything could be explained with images or videos. I can't do that at the moment.
Q. Indeed. Well, I'm rather exhausted from reading, and it's apparent that you're not going to give me screenies, so I'll end it here. Thanks for the answers, and good luck with LT. I look forward to that (semi)weekly log.
A. Thanks for listening, imaginary forum member.
Statistics: Posted by JoshParnell — Mon Jan 23, 2017 12:08 am
Thanks, appreciate the sentiment. All is well, although it's been a bit busier than anticipated, but such is life. Recap of life in the past few months:reegs87 wrote:I do hope that all is well with Josh. I would imagine that the guy has a tremendous amount of pressure on him. That being said it would be lovely to see an update sometime in the near future; this forum was one of my regular haunts....
Thankfully not, so far LTEngine 2.0 (pff, I know, there's been a lotttt of refactoring over the years, but this is the first time I actually split the codebase) has been a joy to work in. I'd be lying if I said I wasn't anxious in the slightest about what kind of performance we'll see when I have all the logic running. But, that's kind of the nice upshot of having a hybrid engine -- if performance is problematic, you tell more of the code to come to the dark side...eh, the statically-compiled side. So far, though, all is well and only going to get better as I continue to improve the JIT engine to be able to handle harder cases (hence, be able to convert more of the code).kostuek wrote:I'm afraid, he may have hit the same wall as he did with LTSL - his Python business may still be too slow. If this is the case, he is probably back in his corner, thinking about what the hell to do now.
Statistics: Posted by JoshParnell — Fri Aug 12, 2016 12:53 pm
I think you've got most of the general idea, but I'll explain the actual implementation anyway (and why it is efficient). A blueprint is a pointer to another blueprint (its 'parent' or parent directory in your model), plus a list of attribute operations (you can think of that as a very, very limited script, but really it's better thought of as a 'diff' between the parent blueprint and itself -- an object-attribute-space differential, so-to-speak). This is highly memory efficient, as we require very little memory to make lots and lots of slight variations of an object. If the variation is slight (for example, a delta in just a single attribute), then the memory required for the BP is very, very small (quick mental calculation says ~20 bytes on 32-bit machine, ~32 bytes on 64-bit). "Absolute Original" blueprints (i.e., those that haven't been derived through researching a stem of an existing blueprint or implicitly derived by modifying an object (note that virtual blueprints are not visible to the player, but rather an abstract BP that exists solely to help the AI understand and quantify the nature of an object that's been modified -- by keeping an up-to-date virtual blueprint for the object, we allow the AI to apply the same reasoning to all blueprints when it comes to any type of analysis)) are simply blueprints whose parent field is 'None' and whose attribute operations consist of setting all attributes to their correct values (in other words, they're a diff with a 'null object', so to speak). These are significantly bigger than derived BPs, especially when they are for objects that have a 3D representation (because it is the base BP that actually holds the model). This paradigm of using chains-of-diffs pops up frequently in LT. It's a really, really good way to save memory when we're in procedural land where there's a huge amount of generated content, but where that content often has significant underlying similarities that can be captured in this original + diff + diff + ... manner. Kind of like prime factorizationHyperion wrote:Module instancing is actually proving to be a slightly difficult problem to hash out. Getting a good way to track 10,000 eventual variations on a single blueprint for every single blueprint without making the system cry is probably doable, but is beyond my realm of expertise. Just as a brief outline of my (probably dumb) thoughts, because this isnt really the place for it:
Blueprints are folders, but also instructions coded with the particular Tech stats. Inside the folder is a registry of every unique instance yet made and its stats, each tagged with the owner and where it's used. The owner and usage tags change freely via trade & plunder.
The currently simulated blueprints are known scripts, executed as necessary, changing the stats of the given instance.
Players & NPCs can also execute their own scripts (aftermarket modifications, improved/shoddy construction techniques & materials, overclocking, etc)on a particular instance which also changes the instance stats, but are wholly different from blueprint scripts. Such modifications don't affect the registry serial, but can affect the Human-readable name.
Destroyed instances (or intact but attached to destroyed ships/stations) continue to exist in the registry for potential salvage and reactivation until cleanup.
Temporary instances can also be attached with semi-random stats to permanent debris fields, but disappear as soon as a player is out of range.
Is this efficient? No idea
Statistics: Posted by JoshParnell — Thu Apr 28, 2016 10:11 am
Fair enough, I can understand all viewpoints expressed in the thread so far (with the exception of TGS's 'nil' expectations for this game -- come on now!)Hyperion wrote:It's been itching at me for some time now, as it probably has for plenty of others. I'll put it simply.
I want proof that development is taking place, that the game is closer to being finished than it was last year.
Not "Things are exciting" or "I can work so much faster now" or "I know what I'm doing" Not words and rumors about release date leaks, but cold hard proof. An image or video of something new, something we haven't seen before. It doesn't have to be much, but unless I missed something, it has been over 14 months since there was a single shred of proof that the game has developed beyond where it was in January of 2015.
Josh, I'm not calling you a liar, and I understand that you're holding your cards tight which is fine, but absolutely nothing since you declared the beginning of Golden Days almost 8 months ago? I'm sorry, but I'm not big on faith, and this total silence is testing those limits. Words and promises won't keep that alive, only evidence would carry me months and miles longer, and I have a feeling I'm not alone.
Statistics: Posted by JoshParnell — Tue Apr 05, 2016 8:54 am
Statistics: Posted by JoshParnell — Wed Mar 09, 2016 5:08 pm
Statistics: Posted by JoshParnell — Wed Mar 09, 2016 5:06 pm
Statistics: Posted by JoshParnell — Wed Mar 09, 2016 5:05 pm
Yes, those were back in the days when I was simply pumping out C++ as fast as I could. And there's nothing wrong with that. I could resume that approach today and have a much lesser form (and non-moddable) of Limit Theory out in a very reasonable timespan (and that's only because I've re-architectured the engine and now know how to prevent monoliths). But that's not going to happen, because, as my conception of Limit Theory matured, modding became something that I simply had to have. I want you all to be a part of Limit Theory's development. I want to see what people can do with this technology over which I have slaved for years. I want to play insane variations of my game that blow my mind. And it's all very much possible. I'm fine with dropping other content (especially content that has crept in since the original design doc) -- it can be appended later via modding. But I'm no longer fine with a non-moddable LT, and this is where the real challenge lies.Zanteogo wrote:It's just from this side of the computer screen I remember the years of LT development where every month massive improvements and changes were occurring and it seemed like you were on the highway to completion. It seemed like everything was coming together. I know that in almost all software, it's the way of things, the first 80% is the fastest, the last 20% takes 80% of the time. However, it seemed you had mostly side stepped this trend with your one man team approach, (for what ever reason). I recall the day when your showed us LT, and the AI was doing it's own thing and reacting in it's own way to changes, and I recall in awe thinking, "it's happening".
I know I am arm chair quarterbacking here, I am merely seeking to understand and to remove my ignorance to the whole thing.
However, to me, it was just before the start of LTSL that everything seemed to.. stop. Everything seemed to be put on hold. For the things that didn't, it's when the circular development seemed to really happen. Again, this is all from the prospective from this side of the computer screen of course.
From what you have opened up to us on your dark days, you admitted to getting stuck on circular cycle of not really moving forward. You also informed us that something you had done to LT had to be undone.
During the half of year of LTSL development it was sold as the thing that would cause a massive content explosion. I know your keeping your cards close, however, so I don't know what you have done since, but I am guessing there has been no explosion. If I am mistaken I and truly sorry.
JoshParnell wrote:Thank you, Flat, for sticking with us and continuing to provide valuable input at every juncture. I hope you know that your words don't go unread by me, and, despite the points on which we may disagree, even in these late hours you continue to provide thoughtful-yet-non-destructive input on the dev process.
I'm sure many people think that their words fall upon deaf ears with respect to me (especially given how little time I have to actually respond to the plethora of discourse on here). Such is not the case (not since the Dark Days, at least). Criticism isn't going to cause me to tear down my whole development approach, but it certainly doesn't pass through my mind without leaving something behind.
Link to original: http://forums.ltheory.com/viewtopic.php ... 80#p115867
Statistics: Posted by JoshParnell — Wed Mar 09, 2016 5:03 pm
Hey Kimny, welcomeKimny wrote:I don't know how many other different ways I can say I believe in him, I trust he is telling the truth, I trust his character, I like him, it's not a personal critique. Really, it's almost like it's necessary to spend paragraphs apologizing before making a criticism. And even I repeating all that in all posts, still one replies that I think Josh is lying, another replies saying I shouldn't distrust his character, another says I should shift to my personal life, you now reply as if I were trying to offend Josh.
I explained extensively in the other posts that on the contrary, I don't want to mix personal and professional. I really like Josh, trust him, etc, etc (second time in a post). I just think he has been in error in what regard not giving one piece of information during 1 whole year. Of course that is worth criticizing. And it's normal to criticize it. He is a professional, LT is a funded game. Sometimes it seems that taking 1 screenshot in an year, or even less, talking a couple of lines about the concrete game in an year, is to put super pressure or to ask Josh something very unusual. Indie developers certainly do not update on their games all the time as Josh did. Also as I said many times now, that's fine and I think he was very right in his change towards focusing in the game (I also have to repeat that all posts...). But it is not true that is normal and acceptable that indie developers go a full year without anything remotely concrete and behave as if it that was a plain fine decision instead of something to apologize for. Much less is usual that people are ok and even repeat in the developer's place that "progress is being made", that we should only thank Josh for everything nice he has (indeed) done so far or for not unplugging our critiques from a forum at the official page of the game!
It's very simple: he's been doing choices and following paths that deserve critics just as we would do with any developer. THAT is just what I meant by it's time to criticize Josh's approach to it. JUST that. But anyway, from now one I will reply with a signature that repeats automatically:I trust Josh's word, character and passion, I like him and admire him personally. Yet critique some of his decisions as I would do to other professionals (and that's a sign of respect). Btw, that's the third time self-justifing all that in the same post....
Statistics: Posted by JoshParnell — Wed Mar 09, 2016 4:59 pm
Statistics: Posted by Talvieno — Wed Mar 09, 2016 4:54 pm