Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

1387105 Posts in 66514 Topics- by 59066 Members - Latest Member: MonZop

January 20, 2021, 02:59:49 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsCommunityDevLogs16-bit networked RPG project
Pages: [1] 2
Print
Author Topic: 16-bit networked RPG project  (Read 1847 times)
internationalfish
Level 0
***


View Profile
« on: March 10, 2020, 12:19:13 AM »

Concept
An SNES-era JRPG with turn-based (possibly ATB) combat. More importantly, to me, a server component that enables all sorts of live updates and player-to-player interaction. I'm working on seeing if I can keep the code and data modular enough that adding features is less of a core overhaul and more of a "well, this needs to be subclassed and it'll need a new prefab, but that's it" thing. Within reason.

Technology
Server: Clojure + Redis
Client: Unity + Websocket connectivity

Status
Maps are generated on the server and sent to/rendered by the client; the player can move around and their position will be checked and stored on the server (invalid move requests are reversed). Menus are generated via JSON loaded at runtime.

Latest eye candy:

Menu system work:



Battle system start:



Current TODO
  • ATB implementation in GUI and on server
  • Hook up existing basic battle menus to UI
« Last Edit: April 10, 2020, 04:19:18 AM by internationalfish » Logged

internationalfish
Level 0
***


View Profile
« Reply #1 on: March 10, 2020, 08:18:19 AM »

Hit a few snags getting the tile rendering right (Unity is kind of clever about how it pulls sprites out of a sheet -- it'll ignore parts if they're entirely transparent -- but that means you have to be careful about how you use offset indices), but I did manage to render a map generated by the server.

Gentlemen... behold!



The little dude actually is animated, but it's hardly worth figuring out how to take animated gif captures for one two-frame sprite animation... not all that interested in fighting with that until there's at least some motion going on. Although I will say Unity's 'Pixel Perfect Camera' seems to be working very well.

This is really bare-bones; the server's just sending tiles and a style reference. Need to at least get it sending whether each tile is passable, which shouldn't be a big deal... switching from straight sprites to Tilemap in Unity would probably be a good idea, but last time it was a completely nightmare. Didn't even work in webGL players at that point, which was the only platform I was exporting to, and left a seriously sour taste.

I did refactor the auth code on the server, so that's looking a lot cleaner. And I found a reasonably well-reviewed Bluetooth controller for about 15USD. Going to go straight to that since I'm not targeting mobile/web this time. It'll be here on Thursday. Smiley
Logged

internationalfish
Level 0
***


View Profile
« Reply #2 on: March 11, 2020, 12:37:29 AM »

Turns out peek is a really nice gif screen cap program. So that's no problem. Smiley

Speaking of which:



[edit: Turns out not having SSL was killing my images. Got that corrected.]

I updated the map format to support tile attributes; at first that's just whether the tile can be walked on at all and whether there's already someone on it, but now that that's there, any attribute can be added.

Unity does support handling collision-based "you can't walk there" for tilemaps, but since I want control over that from the map definition anyway, I'm just using a Tile subclass that has a boolean to define whether you can walk on it. I'm guessing it'll be much lighter-weight.

The major thing missing from this is server-side action validation, i.e. asking permission to move to a given tile. That will take a little longer, but even more so than map tile attributes, it's important groundwork that will generalize well.
« Last Edit: March 11, 2020, 04:15:27 AM by internationalfish » Logged

internationalfish
Level 0
***


View Profile
« Reply #3 on: March 12, 2020, 10:36:07 PM »

Despite actually looking slightly worse (the whole 'walls' thing on dynamically generated maps hasn't been a priority yet), I've made a significant amount of progress.

The client now asks permission for movement! The server will check whether the player is where they say they are, whether the place they're trying to go is passable and unoccupied, and respond appropriately. The client starts the walk animation immediately but will revert to its original position if the server says no.



No, it's not good practice to have your credentials in the logs, no, that's not my online banking password, and yes, it's set up for SSL.

While the map is obviously super simple right now, it is being passed to the client on successful authentication, so I'm pleased with that.

Aside from crashing and hanging left and right (seriously, it's constant), Unity has a by-design behavior that I can understand but still caused a bit of an issue: It refuses to run any of its own functions outside of the main thread. Well, I've got threads flying around everywhere; in particular, aside from the normal don't-hang-the-UI coroutines, I'm getting messages via websocket from the server that are handled in parallel.

Thing is, those threads can't use any Unity functions, and now that I'm wanting to render a map in response to a message, that means I have a problem. Fortunately, I found a really great little tool someone put together to queue requests for the main thread to run, and it works like a charm. Smiley

My Clojure code got cleaned up quite a bit, then got randomized again. So I do have some more namespace cleanup to do, but the actual quality is pretty good -- both client and server -- compared to what I've hacked together on these attempts in the past, which is encouraging.

So that actually clears up my original To-Do list. I think I might take a break (kinda) from sprites and work on some UI. I expect menus to be the largest interaction point in the game, so I really want to get that right.
Logged

internationalfish
Level 0
***


View Profile
« Reply #4 on: March 13, 2020, 06:32:57 AM »

Aha! It speaks!

There's a lot of good dialog managers out there for Unity, but they tend to be really heavy, and since my logic and data is going to be in Clojure, I figured I'd just get that old-timey text box action working on my own. Oddly enough, it actually worked out the way I expected.



Anyway, this takes an arbitrary string and cuts it up by spaces (will need to tweak that logic for languages that don't use spaces), figures out when there should be a newline and adds it, and stops before it overruns the text box. This panel will need an indicator that there's more text and, obviously, the ability to wait for input and display the rest. Not tonight, though.

There's a separate panel that will display shorter messages on the top of the screen; that one will just pause before replacing the existing text, so that's slightly different.

No server component for this yet, but it's all IEnumerator goodness already anyway, so it's ready for queuing as soon as I teach the server to send messages. :D

Also, I haven't even made an effort to keep the various pixel sizes consistent. Which is eventually probably going to look silly, but that's yet another down-the-road-if-ever thing to worry about.
« Last Edit: March 13, 2020, 07:27:27 AM by internationalfish » Logged

internationalfish
Level 0
***


View Profile
« Reply #5 on: March 15, 2020, 07:55:25 AM »

Something fairly substantial on the client side this time, though it might not look that way. Smiley

Two important things are now happening. First, dialog has pagination! I started off with text that was too long to show in one box, since the worst case scenario is usually the best place to begin. That's handled now.



More importantly, though, there's now a stack of input targets. So if you're the top menu (or whatever, provided you implement the right interface), you'll get input only when you should. So in this gif, even though you can't see it, I'm button-mashing while the dialog is up but my poor sorceress just isn't going anywhere, since she's not at the top of the input stack.

I'm also really fond of the little bouncy triangle.
Logged

internationalfish
Level 0
***


View Profile
« Reply #6 on: March 15, 2020, 08:12:28 PM »

After a bunch of struggling with resolution (I still need to nail down exactly how the Pixel Perfect Camera is going to scale itself, which seems like it's going to be a struggle), I got everything at least looking different at 1x scale. I hadn't realized I'd been setting the dialog sprites at 0.5x, and then I forgot and wasted a bit of time trying to figure out why the new one didn't look like the old ones despite using the same 9-patch asset. Ugh.

I do think it's looking OK, though.



I've been playing with controller input as well. I did not realize the XBox controller reversed the A/B and X/Y positions compared the SNES controller... I guess that speaks to how out of touch I am with consoles. Unity solves that by referring to them as north, south, east, and west, which I think is an interesting way of addressing it. Though this makes me think about how I'm going to go about letting users set their controls, which... eh. Not really looking forward to that.

For now, though, I'm on menus. Dialog boxes are easy enough, just text with a few caveats. But now it's about getting selectable options in and wiring up arbitrary behaviors in response to selections. Expecting this to take a little while.

Also, at the moment, I'm generating the map tile references the client uses to pick sprites and just sticking them in a directory the client and server can both access. Obviously not going to fly. So, to give myself a server-side task to work on, I'm going to get hash checks and updated file send in place, so I can completely do away with the shared folder. Shouldn't be a very big deal, but it'll feel good.
Logged

internationalfish
Level 0
***


View Profile
« Reply #7 on: March 15, 2020, 11:12:21 PM »

Clearly getting a little more comfortable with the ins and outs of C#. Smiley

There's still a lot to do (dealing with vertical and horizontal overflow, delay-then-scroll on holding up or down, getting this to generate function calls based on JSON from the server rather than the easy way with normal C# in particular), but the basics came together faster than I expected.

Mr. Death demonstrates invoking and backing out of a menu, then invoking it and making a selection, which results in an encouraging message.



There's a lot of hard-coded pixel offsets that I'm sure are going to make me cringe when I get around to nailing down client resolution, but... meh. It's just not a problem I want to address right now.
Logged

internationalfish
Level 0
***


View Profile
« Reply #8 on: March 17, 2020, 06:54:22 AM »

I did a lot of major refactoring around how maps and data are handled, particularly how they're retrieved from the server and how everything gets loaded at runtime.

Then Unity just started segfaulting. Every time I tried to open it.

I'm not going to tell you what to do. I'm not going to tell you not to use Unity. But GODDAMNIT I've lost so much time to this program's bullshit.  Roll Eyes

[edit]
In the interest of honesty... I have to kind of apologize to Unity. This was mostly not its fault.

It turns out it's gotten weirdly hard to install a decent SNES emulator. Which is thoroughly strange. But that's how it is, at least on Linux, and it led me to do a lot of root work I shouldn't have in the pursuit of snes9x. This wasn't an issue for anything else, but it destroyed Unity, which got confused because there were extraneous nvidia libraries on a system that didn't actually use them.

I do reserve the right to be a little angry about it, since there's no reason this should've mattered, but I do take some responsibility.

Unfortunately, now that I figured it out... the minor version of Unity I was using is no longer available via their launcher. So I'm actually stuck with the shit that presumably still can't slice a sprite, so thanks for that, guys.

Anyway... I got this shit running again just to rediscover the bug I was trying to fix when it broke. Which was disheartening. Fortunately, I just got a nice set of headphones (I've never actually had decent headphones, and work got me some so I could participate in calls without pissing everyone off with my cell phone headset audio quality), so I'm rocking out to things I don't want to admit to here.

Be safe and make games, friends.
[/edit]
« Last Edit: March 17, 2020, 09:13:09 AM by internationalfish » Logged

internationalfish
Level 0
***


View Profile
« Reply #9 on: March 19, 2020, 04:50:15 AM »

So it turns out there's not really a consistent cross-platform way for Unity to persist files that aren't part of the installation locally. Not really their fault; just how it is targeting so many different platforms, I suppose.

Fortunately, the stuff I wanted to keep synced is fairly small JSON files, so pulling them down any time they're needed isn't a big deal. Got that in and working, so the work I put into hash checking and updating got tossed... ah well.

'Upgrading' from Unity 2019.2.x to 2019.3.x broke a bunch of things, predictably. After getting that working and fixing a map loading bug (one that I actually caused; it's almost refreshing at this point), I'm already kind of meh on doing anything else... the next substantial thing I have on the list is making a multi-panel dialog, which is honestly a little daunting.
Logged

internationalfish
Level 0
***


View Profile
« Reply #10 on: March 30, 2020, 05:08:24 AM »

So it was nice having the fun text dialog boxes going, and I imagine they'll come in handy, but I really wanted to get generic menuing (there's that menu-as-a-verb thing again) implemented.

I got most of the way there, but I was spending too much time screwing around with getting the data structure initializations right in C# just to get test data in... so I dropped that and went straight to generating menus from JSON. I'm very pleased to have this working.



The menus there were generated from this (and navigated with this, which I just got recently and am completely in love with):

Code:
{:panels [{:dimensions {:width 0.3}
           :options
           [["Heading" nil]
            ["Pick me!"
             {:action "panels"
              :panels [{:dimensions {:left 0.3
                                     :width 0.7}
                        :options
                        [["What would you like to do?" nil]
                         ["Party" {:action "panels"
                                   :panels [{:dimensions {:left 0.1
                                                          :top 0.5
                                                          :width 0.4
                                                          :height 0.2}
                                             :options [["Woohoo!" nil]]}]}]
                         ["Relax" {:action "panels"
                                   :panels [{:dimensions {:left 0.3
                                                          :top 0.5
                                                          :width 0.4
                                                          :height 0.2}
                                             :options [["Ahhhh." nil]]}]}]
                         ["Contemplate" {:action "panels"
                                         :panels [{:dimensions {:left 0.5
                                                                :top 0.5
                                                                :width 0.4
                                                                :height 0.2}
                                                   :options [["Hmmm..." nil]]}]}]]}]}]]}]}

Well... the JSON representation of that (it's a Clojure data structure). But this is a lot more compact than pretty-printed JSON, so hopefully it's easier for everyone else to read as well. If nothing else, it won't double the length of this page.

Anyway. The action parameter value panels tells Unity it needs to use these values to render one or more menu panels, as well as what options they should have in them, and what action those options should support (if any; a null/nil action is considered a heading and not an active menu item). They're added to the current menu's focus stack; a menu can have any number of panels, and it sends input events to the topmost one, which will close and destroy itself when you back out of it.

While this is potentially useful for generating menus on the server, and it'll certainly be used that way for things like item, unit, and equipment menus, I plan on having all of the menus built from JSON, even if they're baked into the build. It's just massively easier and less finicky to switch things around and fix them without introducing new bugs when it's in a dead simple notation like this than if it's baked into a C# file somewhere. Bleh.

The only other thing I had lined up with this -- which I expected to take longer than it did -- was centralizing input handling so changing bindings would be easy. That sounds... really dull, though. So I think I might start on battle mechanics, now that I've got the menus working. Smiley
Logged

internationalfish
Level 0
***


View Profile
« Reply #11 on: April 04, 2020, 03:21:51 AM »

More menus! It's almost the same as the last gif, with some important differences (not least of which is the doubled frame rate).



The bottom left 'GOLD' panel is the same type as the three small submenus. The difference is the character rendering delay. GOLD is zero, and the little ones are progressively longer.

That was easy to implement thanks to having refactored the basic UI panel stuff out into its own class and having all of the actual rendered panels as subclasses that have their configuration passed in (via JSON parsed further up the chain, either from a local file or the server).

Another one that I actually forgot I hadn't mentioned is that I switched the map format around to make it a lot easier to process. Which had the (intended) side effect of making walls much easier to fill in given an initial map of just walkable floor tiles. So you can see the walls there. The only thing I haven't done yet is inner corners, which I think will be a bit more of a hassle, but not too much. There's probably a trick I'm missing... meh. I'll figure it out.

There are more tweaks and improvements to make, but now that the fundamental refactoring is done, I think it's battle UI time. Which means handling parties and turning a party of units into UI elements. Smiley
Logged

internationalfish
Level 0
***


View Profile
« Reply #12 on: April 10, 2020, 02:16:57 AM »

Battle UI started! Smiley

It's just the really, really basic layout, so it's not exactly amazing to look at. But... here you go anyway!



Now, I know Ms. Jacalyn Anity might not be the most common name, particularly for a, uh, grizzly bear. But she is a very fancy bear.

Really, though, I'm used to the names library for Python, which generates way less interesting names... the one I found for Clojure tries way, way harder. It ended up being pretty funny, but it also pointed out something I'm going to need to deal with: Choosing name length limits and dealing with the actual length of names in the UI. Handling the length of strings in these text panels is something I've already handled quite a bit, but this is certainly adding a bit to it in some specific panels.

This update would be really, really lame... more lame than it looks... if this stuff -- the menu panels, the parties, the units -- weren't all coming from the server in JSON. Which, still, I suppose doesn't seem huge, but it's a really good first step to making almost everything data-driven in the client. So I'm really pleased with that.

It was also a larger pain in the rear than it should've been to get the parties to render on a diagonal based on how many of them there are (which is the reason I have one party with three and one with four units, to make sure the client is staggering them correctly). While this particular layout will work for four-member parties, it doesn't help for traditional FF-style enemy packs that tend to be grouped horizontally. So that's something else I'll need to work on, but for now, I'm pleased with the progress.

Next on the menu will probably be:

  • Menu display templates (first one: Unit name + ATB bar for right-side battle menu)
  • Displaying battle options (which are already being generated but not displayed)
  • ATB progress on the server and messaging to the client when ready
Logged

internationalfish
Level 0
***


View Profile
« Reply #13 on: April 17, 2020, 05:59:24 AM »

It's been fits and starts, but I'm very pleased with the progress since last time. And, once again, it's a bit hard to see, so you're going to have to take my word for some of it (or not, but... what would really be the point?).



The fun thing about this is when the ATB gauge hits. Or... just before it hits, since I clearly haven't quite done a good enough job getting the UI timed correctly. But the battle menu pops up when the server knows its ATB gauge is full, based on starting at zero (which will change to a normalized value across all units in the fight, because waiting while nothing is happening is not entertainment) and its fill rate.

Also impossible to see here is that other units that hit their ATB limits are getting notifications from the server, and are being queued up for the UI.

Problem #1 here is clear from the lack of opacity on the arrow when the battle menu comes up: For some reason, that panel doesn't think it has focus. And I'm hard pressed to argue with it, really, because I have utterly failed to document the way I've implemented pretty much EVERYTHING up to this point, so I'm not even sure why the non-battle menus... actually work. And they still do. But this one doesn't. So that's next on the list.
Logged

internationalfish
Level 0
***


View Profile
« Reply #14 on: April 20, 2020, 03:11:20 PM »

When I wired in the ATB timers, I made sure the UI would queue units who were ready but didn't have focus, so it ended up being fairly trivial to get available unit switching implemented (minus the standard Unity struggles, of course).



And while I didn't think to show it in this little demo, the battle menus do get focus correctly now. I think the biggest piece of the battle flow should be next: Getting single- and multi-unit targeting working in the UI and wiring up that logic on the server.

I haven't mitigated the ATB gauge delay yet, though I've started getting a server-client lag check in place to hopefully get it a lot closer to being accurate. I might punt on finishing that for now, though; I really want to get basic attack and maybe defend working.
Logged

internationalfish
Level 0
***


View Profile
« Reply #15 on: April 22, 2020, 04:27:44 PM »

Going through the slog that was getting targeting working (which I... kind of... did), and constantly finding more and more TODO items in the code, it became clear that I'd buried myself in cruft.

So I scrapped the client and started over.

Well, not completely. Most of the animation and rendering code is fine, it's just that a lot of the control flow needed serious refactoring that would've taken more time to try and do in-place. Which is already going a whole lot better, thanks to actually taking the time to plan the client out in terms of code this time.

Among a lot of other improvements, I'm also putting some effort into getting the UI pixel sizes to match each other. It'll take a little more time to see if that pans out.

For now, though, one of the initial bonuses is handling the active party as part of the User data structure, which -- among other way more important but less UI-visible things -- allows easy party leader switching in the map view.



The biggest reason for this overhaul was the clusterlove that menu handling was turning into. I'd painted myself into a corner by assuming anything that could have focus (i.e. handle input) would, could, and should be modeled as a menu panel. That turned out to be totally wrong when I got to the unit selection UI, which still had to fit into the input management hierarchy, and that required enough ugly hackery that it was no longer worth even attempting.

The concept is still similar, but rather than panel-centric, it's treating UI components as a stack of 'layers,' with a layer either being focusable (handling input) or not, and the top layer on the stack being delegated input, provided it's focusable. The map grid, which contains the tilemap, is currently the only focusable layer, and it's being delegated input as intended, so that's a start.

Not quite sure yet how I plan to handle rendering order of focusable and non-focusable UI layers, and it may end up making sense to just have focusable layers manage their own non-focusable layers and just have the focus manager ignore them, so that's going to be something to figure out soon.

And now, on to reimplementing menus. Smiley
Logged

internationalfish
Level 0
***


View Profile
« Reply #16 on: October 21, 2020, 01:23:22 AM »

So a lot got in the way -- the whole pandemic thing hasn't helped, and my young spawn also demands some time occasionally -- but I finally got back into working on this a bit, so I figured I'd resurrect this thread.

After the last update, I made a whole lot of progress on UI layer handling (including lots of effective focus shenanigans), and today I finished most of the important work involved in moving to a single thread per battle, which is a massive scalability improvement. Also just generally a lot easier to work with, so that's also something. It's also set up -- as I wanted but haven't really prioritized -- to enable any number of human players to control any number of characters in either party in a fight, so that's pretty sweet.

I'm to the point where it's time to get in-battle actions going. Starting with just basic attack and defense, this should lay the groundwork nicely for whatever spells/skills/whatever I'll hopefully get running down the road.

If job hunting and, you know, actually doing my current job don't get in the way, hopefully I'll have a bit of a visual aid this weekend or early next week. Smiley
Logged

Rogod
Level 1
*



View Profile WWW
« Reply #17 on: October 21, 2020, 02:01:33 AM »

Can't help but notice the sprites in this are also in Orna (for Android).

Did you copy them or did they copy you? Or did you both copy something else xD? (Or is this some generic Unity sprite pack I'm unaware of)
Logged

internationalfish
Level 0
***


View Profile
« Reply #18 on: October 21, 2020, 02:19:55 AM »

Can't help but notice the sprites in this are also in Orna (for Android).

Did you copy them or did they copy you? Or did you both copy something else xD? (Or is this some generic Unity sprite pack I'm unaware of)

Good eye. Wink They're actually from an Oryx sprite pack, specifically the 16-bit fantasy tileset. It costs a little cash, but the prices are absolutely worth it for the quality, and they've got some nice, beefy products.
Logged

Rogod
Level 1
*



View Profile WWW
« Reply #19 on: October 21, 2020, 02:45:43 AM »

Ah awesome ok :D
Logged

Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic