[Phaser 3 – WIP] Fantasy Sphere RPG

Few days ago I have decided to start an RPG project, as that’s what I’ve always wanted to make. I will be fairly limited with graphic assets and time, but at least the coding part will be fun. I will make do with what I have available.

Right now I have depth sorting implemented:
depth_sort

I’m using Time Fantasy art assets.
Tiled for level editor.
Haxe as programming language.
Phaser 3 as framework.
Coffee as fuel.

So far I’ve went through map loading (surprisingly simple in Phaser 3), animations based on keyboard input and basic collisions using Phaser’s Arcade.

Then I switched to using Differ for collisions, because Phaser’s Arcade physics couldn’t handle custom shapes per tile by default. Given that I expect more requirements from the collisions/physics system, I like having more control over things instead of letting Phaser handle it all for me.

After that, it was time to refactor all the code, because it was getting messy. I choosed to use ECS architecture, because I used it before and I find it very nice for these kind of games. Especially considering how big the game might grow, it’s important to keep the code clean. I was deciding between using Elias Ku’s ECX library and Kevin Leung’s ECS. Ultimately it probably doesn’t matter, but I chose Kevin’s.

At this point the ECS consists of RenderSyncer, KeyboardInput, Movement, PhysicsDebugDraw, PhysicsSystem systems, and Velocity, ActorState, DifferShape, InputControllable, Position, Renderable, StaticCollidable components. This will change a lot as the work continues.

Next I made a custom preprocessor for Tiled level files. I’m converting them to custom JSON that contains only the data I need, in format the game expects. This also allows for making rudimentary checks against typos and missing data. It also means I’m no longer using Phaser’s tilemap loader, and instead had to write a bit of code to populate the tilemaps myself. While this is some extra work, it allows for special handling.

Last thing I did was implement depth sorting. Phaser can’t render different tiles at different depth, or allow you to insert something (like a moving character) in between tiles. If you look at the GIF on top, you see the character can move behind and in front of the tree log and the sign board. If they were part of a Phaser’s tilemap layer, it wouldn’t work. Instead, I mark the layer in Tiled as requiring depth sorting, and the game then creates individual depth sorted sprites. This way I didn’t have to change the level editing workflow and won’t need to manually handle future similar cases.

Next I plan to work on some UI, changing location (loading different maps, like insides of a building), NPCs and interaction, and combat system.

11 Likes

Looks really cool! I’ve always been interested in HAXE.

Keep us posted.

Since the last devlog there were 10 commits between 2019/01/27 and 2019/02/15, totaling 21 commits.

I started out by adding new type of objects to my Tiled map.

message_editor

A bit more messing around and I can now have basic message interaction in the game.

That included adding overlay UI system, some refactoring, support for nineslice scaled ui elements. Handling events between various ECS systems without tight coupling (Keyboard Input System sends an Interaction event that Interaction System then handles).

I also refactored how I change what animation to play on a character. Before it was explicit from keyboard input, but planning forward I changed it to be implicit from actor’s velocity. This will work with different input systems (point and click) and also for characters controlled via AI.

Then I added our first NPC. Meet Rufus.

friend

Since I wanted to play with our new friend, it was time to add some AI.

I decided to implement Behavior Trees. In the ECS spirit, they are completely stateless (the tree/logic itself doesn’t store any data, everything is kept on entities). I define them in XML (which will be improved later), and they compile down to basically an array of functions. Since they are stateless, the same tree can be used to run any number of entities.

behavior_tree

That’s it for this dev log. As for ECS changes, I’ve renamed Movement system into InputMovement, added AISystem, ActorAnimation, InteractionSystem systems. Also added AIState and Interaction components. For other parts, added UI and Overlay Phaser scenes, and MessageBoard UI element.

In the next dev log I will talk more about Behavior Tree AI and my approach to it.

1 Like

Since the last devlog there were 13 commits between 2019/02/16 and 2019/02/22, totaling 34 commits. I have worked 35 hours during this period, bringing the total to 83 hours.

This one is entirely about messing with AI, iterating and refactoring the approach.

Initial Approach

It started with basic xml Behavior Tree from the last devlog. First thing I did though, was updating Haxe to version 4 Release Candidate, in preparation to using inlined markup.

Truth is the xml in the previous devlog wasn’t really used. It was just a template for how I would want it to look. What it actually looked like in code was:

forest = [
	{ behavior: 'Sequence', child: 1 },
	{ behavior: 'Run', sibling: 2, config: { angle: 0 } },
	{ behavior: 'Run', config: { angle: Math.PI } },
];

Where each behavior name mapped to function(nodeId:Int, entity:Entity). Why a function and not some class instance? Because in the ECS spirit, the state, i.e. all the data, is supposed to be stored inside entity’s components. The behavior tree itself should be completely stateless.

So for example Sequence, which needs a state to remember which child it’s currently executing, would use the passed entity to get the AI component and read/write the state there.

But writing it out like in the code sample above is pretty tedious and very error prone. The hierarchy of the tree is mapped using child and sibling properties, which simply contain an integer index pointing to another behavior. Doing this by hand makes my brain hurt.

Macro Powered

Haxe macros to the rescue!

With a bit of magic, I can achieve the same result from the XML file at compile time. Generating the same code by simply doing forest = AIParser.parseAI('data/ai.xml'); Of course I had to write the code to actually do that.

But the behavior logic is still defined as a function, mapped to the proper behavior by a string. I don’t like strings. Too easy to make typos and they often move errors from compile time to runtime. Solution? More macros!

What I did was I turned the Behavior into a class (I know, I know, I said no state and all, but keep reading). Now every Behavior has a class name and has to extend from the Behavior base class. It also made all the child, sibling properties fully typed.

So instead of array of, essentially string names, there is now array of Behavior instances. What about the state? Well, behaviors still need configuration. The child and sibling are part of that. So having instances makes sense. All those properties are final so I can’t accidentally rewrite them. So instead of { behavior: 'Sequence', child: 1 } there’s now new Sequence(1). If the behavior has more properties, they are all added in the constructor, all fully type checked.

But if there’s an error in the XML, while the macro can report it, it might not be entirely obvious what the error is, as inside XML all we have are strings.

Inlined Behavior Trees

Haxe is awesome, I hope that’s clear by now. I mentioned inlined markup support, what is it? Shortly, it allows me to write the XML right inside the Haxe source, process it via a macro and report back. That means I get syntax coloring, errors reported right there, as I write the code, and bunch of other benefits.

I have skipped a couple of iterations, but end result is basically that the behavior tree is declared directly in the code, fully typed and pretty (prettier than here, as the web highlighter doesn’t handle it correctly), like this:

public static var DoggyRun = 
	<Sequence>
		<Run angle={0} duration={1} />
		<Run angle={Math.PI} duration={1} />
	</Sequence>

And the actual behaviors are declared as classes like this:

class Sequence extends Behavior {
    function init():ChildData {
        return {
            child: this.child
        }
    }
    function execute(data) {
        while(true) {
            var child = forest[data.child];
            var status = runOther(child);
            switch(status) {
                case Success:
                    if(child.sibling.valid()) {
                        data.child = child.sibling;
                    } else {
                        clearData();
                        return Success;
                    }
                case Failure:
                    clearData();
                    return Failure;
                case Running:
                    return Running;
            }
        }
    }
}

The fun part about this is that the init function declares state the Behavior needs, which is stored on the entity’s component during execution. If the Behavior doesn’t need state, the code to handle that is entirely removed. It’s also fully typed, so for the data parameter in execute I get proper code completion and error checking.

Also if you notice the runOther and clearData, they aren’t declared in every Behavior, and they actually aren’t even declared in the base Behavior class. How so? The macro that processes the class will check what needs to be done and only include the code if it’s actually needed, with exact inlined code for the logic, right there where it’s called. That effectively means there’s zero runtime overhead for unused features and when the behavior runs, it’s actually just a single method without any function calls.

Practical Test

First actual use of all this was taking our Doggy for a walk. He keeps running around a log, when he notices the hero, starts circling around him, but will return back to running around the log if he gets too far from it.

I also quickly added support for “barks” for this test. They are a way for an NPC to convey emotions and such.

All that is powered by this behavior tree:

<Sequence>
	<MarkPosition mark={'spawn'} />
	<UntilFail>
		<Selector>
			<Sequence>//either find interest and circle it until too far away
				<FindInterest radius={70} interestingEntities={interestingEntities}/>
				<BarkAction engine={engine} type={BarkType.Icon(ExclamationRed)}/>//bark when found
				<Parallel>
					<Sequence>
						<UntilFail><DistanceSmaller value={200} from={'spawn'} /></UntilFail>
						<AlwaysFail><BarkAction engine={engine} type={BarkType.Icon(Question)} fast={true}/></AlwaysFail>
					</Sequence>
					<CircleAround />
				</Parallel>
			</Sequence>
			<Parallel>//or follow path, if close enough
				<DistanceSmaller value={150} from={'spawn'} />
				<AlwaysSucceed><FollowPath path={paths.get('tree_log_walk')} /></AlwaysSucceed>
			</Parallel>
			<Sequence>//otherwise we are lost, run home!
				<Parallel>
					<AlwaysSucceed><FollowPath path={paths.get('tree_log_walk')} /></AlwaysSucceed>
					<UntilSuccess><DistanceSmaller value={50} from={'spawn'} /></UntilSuccess>
				</Parallel>
				<BarkAction engine={engine} type={BarkType.Icon(HeartFull)}/>
			</Sequence>
		</Selector>
	</UntilFail>
</Sequence>

And this is how it looks compiled:

var forest = [];
forest.push(new ai_behaviors_Sequence(forest,0,-1,1));
forest.push(new ai_behaviors_Run(forest,1,2,-1,0,1));
forest.push(new ai_behaviors_Run(forest,2,3,-1,Math.PI,1));
forest.push(new ai_behaviors_FollowPath(forest,3,-1,-1,paths["tree_log_walk"]));
forest.push(new ai_behaviors_Sequence(forest,4,-1,5));
forest.push(new ai_behaviors_MarkPosition(forest,5,6,-1,"spawn"));
forest.push(new ai_behaviors_UntilFail(forest,6,-1,7));
forest.push(new ai_behaviors_Selector(forest,7,-1,8));
forest.push(new ai_behaviors_Sequence(forest,8,18,9));
forest.push(new ai_behaviors_FindInterest(forest,9,10,-1,interestingEntities,70));
forest.push(new ai_behaviors_BarkAction(forest,10,11,-1,engine,gui_BarkType.Icon(8)));
forest.push(new ai_behaviors_Parallel(forest,11,-1,12));
forest.push(new ai_behaviors_Sequence(forest,12,17,13));
forest.push(new ai_behaviors_UntilFail(forest,13,15,14));
forest.push(new ai_behaviors_DistanceSmaller(forest,14,-1,-1,"spawn",200));
forest.push(new ai_behaviors_AlwaysFail(forest,15,-1,16));
forest.push(new ai_behaviors_BarkAction(forest,16,-1,-1,engine,gui_BarkType.Icon(9),true));
forest.push(new ai_behaviors_CircleAround(forest,17,-1,-1));
forest.push(new ai_behaviors_Parallel(forest,18,22,19));
forest.push(new ai_behaviors_DistanceSmaller(forest,19,20,-1,"spawn",150));
forest.push(new ai_behaviors_AlwaysSucceed(forest,20,-1,21));
forest.push(new ai_behaviors_FollowPath(forest,21,-1,-1,paths["tree_log_walk"]));
forest.push(new ai_behaviors_Sequence(forest,22,-1,23));
forest.push(new ai_behaviors_Parallel(forest,23,28,24));
forest.push(new ai_behaviors_AlwaysSucceed(forest,24,26,25));
forest.push(new ai_behaviors_FollowPath(forest,25,-1,-1,paths["tree_log_walk"]));
forest.push(new ai_behaviors_UntilSuccess(forest,26,-1,27));
forest.push(new ai_behaviors_DistanceSmaller(forest,27,-1,-1,"spawn",50));
forest.push(new ai_behaviors_BarkAction(forest,28,-1,-1,engine,gui_BarkType.Icon(5)));

Bonus video – testing performance – so far so good.

2 Likes

You can see all the devlogs and sign up for the newsletter to get the next ones directly to your email at https://antriel.com/rpg/. :slight_smile:

Cool! Thank you. :+1:

Devlog 4

Since the last devlog there were 17 commits between 2019/02/26 and 2019/03/06, totaling 51 commits. I have worked 39 hours during this period, bringing the total to 122 hours.

Shaders

This time I took a bit of a rest and did something I was itching to try for weeks: shaders.

They are programs that handle the actual process of putting pixels on our screens. Most 2D engines abstract them away and there’s mostly no reason to touch the actual shaders. But you can achieve really nice effects with them, and Phaser does expose a simple way to use custom shaders.

I started with a simple grayscale test, but that’s not very exciting. My initial goal for shaders is to do color grading post-process. That will allow me to change the feeling of the game in various areas by changing the colors. That’s accomplish very simply, by using a color lookup table.

The shader looks at what color a pixel has, looks into the lookup table using the color as address, and applies the value there instead.

The lookup table is made by an artist by modifying a screenshot of the game in some tool, and applying the same modifications to default lookup table (one that maps to the same color).

I’m no artist, so I just used something random I found on the internet for testing:

shader_lut

AI Debugging

When doing first practical test of my AI system it made me realize that tracking down issues is very difficult. I had no easy way to see how the behavior tree is actually traversed at the moment. If my AI wasn’t doing something it was supposed to, I couldn’t be sure if it’s issue in some condition, the actual behavior for that activity, or something entirely different.

So apart from doing various improvements and fixes I thought about how I could debug the behavior trees at runtime. I ended up creating a very primitive system (for now), where the game sends tree data and its current status to a server that’s listening over WebSocket.

I investigated a couple of options and ultimately ended up using zui made by Lubos Lenco which is built on top of Kha framework. I used it because it was very quick to set up and because I wanted to look into Kha ecosystemm as I might have a use for it some day.

Zui is immediate mode user interface library. What that means is that I can very easily map the tree data and status into what’s displayed on screen.

Connected to the practical test from the previous devlog it looks like this:

ai_tool

Having this new tool I didn’t hesitate and made a slightly more complex AI. We can now play fetch!

Next time I will talk about pathfinding, as without it our game of fetch might get a little awkward.

ai_todo

See all the devlogs and subscribe to the newsletter.

Excellent! The game is getting really fun. Thanks for sharing.

1 Like

Wow! I’d be really interested in seeing how you’ve done the behaviour trees! I don’t suppose this is something you’d be willing to discuss in detail?

The third devlog describes my behavior tree implementation in pretty good detail I hope.

But if you have more questions, feel free to ask. What part interests you? There’s a lot of resources about behavior trees themselves, and my implementation isn’t very special really.

Small Untitled RPG Devlog 5

Since the last devlog there were 5 commits between 2019/03/08 and 2019/03/13, totaling 56 commits. I have worked 20 hours during this period, bringing the total to 142 hours. Yes, this devlog is released over a year late.

Playing fetch is fun, but lack of pathfinding turns minor obstacles into insurmountable ones. So I went down the rabbit hole studying how to implement one.

Tiled based games (which this is) often use a simple A* algorithm to search through the tiles. That is pretty easy to implement and works well, but if you remember the first GIF I showed back in the first devlog, you might notice the character is able to walk around the sign post much closer than just a whole tile size away.

That’s because I’m not using a simple walkable/non-walkable tiles collision system.

On top of having more complex collision shapes, I also wanted entities to move naturally towards the target, not from tile to tile. This is achieved by using a navigation mesh. With this approach, I can still use A* to look for paths between two points, but the path will be based on arbitrary convex polygons, not fixed-sized tiles. This can also be faster than tile-based approach, as there’s less nodes to search through.

First problem to solve was generating the navigation mesh. I didn’t want to create one manually, as that would be error-prone and a lot of tedious work. I assumed this would be simple and went into it pretty naively – by cutting out collision rectangles.

Turns out it’s not that simple. This would generate a lot of thin slices. Determining if an entity fits through would also be non-trivial. I thought about optimizing it, but trying to avoid reinventing the wheel, I turned to google for some proper research. Turns out this is quite a big topic, but I found an approach I liked a lot, called Funnel Algorithm. I’m not sure who came up with it first, but a very good resource I found is a thesis called Efficient Triangulation-Based Pathfinding by Douglas Jon Demyen.

I didn’t read it all, as a lot of the math concepts would take me too long to properly understand. But the algorithm itself seemed doable. Everything needed was described in the thesis. While it all seemed simple in principle, it wasn’t a trivial topic once I started thinking about implementation. From generating a triangle mesh, finding a path through the triangles, optimizing it for straight lines and avoiding cutting corners, it added up to quite a task. I estimated it would take me at least a month to implement (looking back, I think it would take longer).

Luckily, there were some implementations of the necessary parts in the open source world. I tried looking for some good-enough looking resources that wouldn’t be horrible to port to Haxe, and to my surprise I found a library implementing it all in a nice package. Enter hxDaedalus.

It’s a mess mesh! It all turned out great and I got it working in a day. Now we can play proper fetch:

See all the devlogs and subscribe to the newsletter.

3 Likes

Small Untitled RPG Devlog 6

Since the last devlog there were 33 commits between 2019/03/19 and 2019/04/09, totaling 89 commits. I have worked 68 hours during this period, bringing the total to 210 hours.

As I started adding more things to my test map, I decided to first improve the workflow and prepare for future development. Tiled supports external tilesets – standalone data files that can be re-used between different tilemaps. Phaser currently doesn’t support them though, and in general there’s no reason to include all of tilemap data in the game. We can do better!

So, first things first, I switched my test map to use external tilesets. That meant I couldn’t load the map directly in Phaser. So I wrote a small tool that loads the Tiled JSON maps and the external tilesets it now references. Then it takes out all the useful data (tiles, layers, collision boxes, object types and positions, etc.) and saves it all into a custom JSON file. Then I had to somehow load it in Phaser. Which mostly meant copying over its Tiled loader code and adjusting it for my new format. I would be lying if I said it went without any issues:

tileset_bug

Now I had full control of everything and could do other necessary things. When rendering, due to floating-point errors, GPU can sometimes sample a pixel too far, causing an ugly effect that’s called pixel bleeding. To fix it, tiles on the texture need to be extruded, which means the pixels on the borders need to be repeated. So I implemented that.

I also took the time to pre-process the geometry used for physics/pathfinding. Boxes near each other could be combined into a single one, improving the generated navmeshes. I used another great Haxe library. A bit of merging and triangle decomposition (as mentioned before, naviagation mesh needs convex polygons to work), and this was the result:

optimized_navmesh

Done with the necessary things, I moved onto the not-so-necessary. For performance reasons it’s also better to use a single texture, as opposed to many smaller ones. Although with modern GPUs it’s not really true anymore, and it’s not like I was hitting any performance limits… but hey, I will take any excuse to code fun stuff. So apart from tile extruding I also added:

  • Merging: Let’s put everything into single texture (for now anyway). Tiles, sprites, animations, text, everything. “My name is Texture Atlas, for we are many sprites.”
  • Deduplication: Tilesets often have the same tile on multiple places, to make it easier for designers to find related tiles. We only need the one, so let’s automatically check for duplicates and remove them.
  • Filtering: We aren’t using every tile from the tilesets. Why drag them around?
  • Whitespace removal: Spritesheets use grid layout, each individual sprite has the same size. That makes finding the correct sprite, and therefore animation, easier (and historically, it saved memory – something we don’t need to care about anymore). But it means a lot of empty space being left behind. We can remove it, in exchange for storing more data about the texture atlas.

There were some funny bugs along the way. This is so-called Phaser’s companion cube. It fills the empty space in your heart, and the good doggy knows exactly what you need:

null

During this time I also wrote and published the second devlog and did some improvements to my blog (adding some Open Graph tags if I remember correctly).

See all the devlogs and subscribe to the newsletter.

1 Like

Small Untitled RPG Devlog 7

Since the last devlog there were 13 commits between 2019/04/09 and 2020/04/04, totaling 102 commits. I have worked 81 hours during this period, bringing the total to 291 hours.

Wow. Devlog for a year of work. Yes. So what happened? Mostly I was busy with other unrelated gamedev stuff. But it is cool stuff, that I will probably implement in this RPG too. I practically didn’t touch the RPG since June 2019 until March 2020.

Debug Draw

After improving the navmeshes last time, I added some debug drawing, so that I can see what’s going on. I’ve went with super Tiny pixelart font. In hindsight, I will have to change this up for something more readable. We don’t need the debug stuff to be pixel perfect.

debug_draw

Combat Loop

Then, excited, I started thinking about combat. Many decisions were made, many are still open for testing and future design. For now, the goal is to have turn-based combat that happens in the same environment as the rest of the game. No battle screens, nor side-by-side battles. This might prove to be a bit challenging in a 2d game, but should be doable.

I added templates to the source Tiled map, so that I could easily describe enemies on the source map. Then I’ve had to adjust my map format for the new entity combat data. Afterwards I did a bit of code design and implemented the logic for a basic combat loop. Without any real AI for now (or rather move-randomly-debug-AI), but I plan on using my behavior tree implementation for this too.

combat_loop

The Future

I was excited about finally adding combat, but I took some time to go over my plans and realized there’s a lot of things I need to do before combat is needed. I looked back at my notes and planned what should the first release look like. I’m not going to talk about it now, but it will be a kind of tech demo. In either case, it won’t be needing combat, but it will need a bunch of other little things.

It was also about time to start doing some basic marketing. So I’ve looked into that, did some updates on my blog, wrote more devlogs and started a newsletter (which you can sign up for here if you yet didn’t). I’ve used EmailOctopus for the mailing list support, because they have nice free limits. I also like that they use Amazon Simple Email Service with my own account, which will keep the cost much lower if when the list grows to hundreds of thousands of subscribers (it sits at a neat 13 at the moment).

For my blog I’m using static site generator Hugo, and I write the posts in markdown. I’ve leveraged that and created a very simple mjml theme to convert the markdown source into HTML emails that I send out in the newsletter.

That was the last thing I did last year. Then last month, finally, I’ve started dedicating some time to my soon-to-be-titled RPG. First step was catching up with devlogs, which is now done. As I’m writing this, there’s nothing further developed yet. I did spend some time on converting the devlogs markdown source into format I can paste into various forums (like bbcode). Turns out parsing markdown is far-from trivial, but using haxe-markdown got me where I wanted to be (although not without issues).

Next I should continue down the marketing path. I need to build a website, spam enlighten more portals with my devlogs, make a discord server, figure out some logo. Then there’s a bit of code maintenance to be done. Well, alright, a lot of code maintenance. But after that, it will be back to the fun things.

See all the devlogs and subscribe to the newsletter.

1 Like

Fantasy Sphere RPG Devlog 8

Since the last devlog there was 0 commits between 2020/04/06 and 2020/05/16, totaling 102 commits. I have worked 40 hours during this period, bringing the total to 331 hours.

Untitled no more!

This has been a productive month, despite not really working on the game itself. As I mentioned in the previous devlog, I focused on marketing. I have also recruited two friends to help me out (well, technically I’ve been talking their ears off since I started last year). As a result of all that, we’re becoming a bit more official. Here’s what’s new:

  • We have a name! Fantasy Sphere is the shared name for all our future RPGs, signifying the universe all the games will be set in. The first one is called Heart Of Harmony, with tech demo Town Of Dotfal coming before it.
  • We have a logo! Which I designed, surprisingly. That’s hopefully going to be the only art thing I have to do.
  • We have a website! Go visit FantasySphere.games. Let me know how you like it.
  • We have a discord! Come say hi.
  • Also Twitter and Facebook. Those probably won’t be very active, but hey, we have them.

Most of the time was spent on the website itself. It took much longer than I expected, which is the norm. I’m not 100% satisfied with it, nor the content, but it’s better than nothing, and better than I expected. I’ve started with a template, but had to fix up a bunch of things. Figuring out how Hugo themes work, how to share content between the new site and my blog. Lot of work went into the gallery page, which will be kept updated as new media is created.

Meanwhile some work was done on a map for Town Of Dotfal by Lotlurien, one of the new team members. I’ve helped out a bit, and have to say that map making is much more difficult than I would have assumed. There is going to be an enormous amount of little details to figure out and do. As we go and learn, we will improve the process. I have an itching to make a full map editor software, instead of using Tiled, but hopefully it won’t have to come to that. At least not until we have more general experience. Here’s a very early sneak preview:

Onward

Now it’s finally time to dust off the code. There’s lot of cleanup to do. I want to decouple a few things into standalone libraries. Possibly improve the AI tooling (as we will need it a lot for the tech demo).

Then I have one experimental architecture idea I would like to try. It’s not a small one, but could be very useful down the road. It’s practically what I’ve spent the past year working on for other multiplayer projects. Since this project is also multiplayer (Surprised? Check the website!), it would be nice if I could benefit from that work here too. More on that if when I get it implemented.

Find out more about Fantasy Sphere.

5 Likes

Maybe I missed it in the write-up (sorry) but when your characters move does their depth update as they ascend and descend the Y-axis so they’re depth-sorted correctly against the environment?

Indeed, they do update their depth. I’ve talked about it in the first devlog’s penultimate paragraph. Basically I have special layers that don’t create tiles, but normal sprites. Within that layer, characters can walk and be depth sorted. The code for that looks like this right now (every frame):

sprite.setPosition(entity.position.x, entity.position.y);
var depth = entity.position.y / 1600;
if(entity.renderable.isElevated) depth += 16 / 1600;
sprite.setDepth(depth);

The 1600 is my test map size (magic number, will have to refactor, 100 * tile_size basically). I think I had some reason why I made the depth be in [0,1] range, but can’t remember now.

1 Like

Fantasy Sphere 2021 Status Report

Pondering The Orb
thumbnail


19 months have passed since the last devlog. Time sure does fly. I’m here to dust off the old websites and mailing lists, and see if it all still works. So, *clears throat*, hi there. Welcome to the exciting new post about what happened (nothing really), what was I doing (a lot!), and what’s gonna happen in the near future (more of the same), and in the far future (exciting stuff).

Where did we go?

Nowhere.

That’s right. No work has been done on Fantasy Sphere. If that makes you sad, imagine how I must feel (very sad). Why? Because I find joy in working on Fantasy Sphere, it’s a goal in my life and… Oh, you mean why was no work done? Right, sorry.

I suppose it comes down to the dream of being an independent game developer. With practically zero marketing skill. Barely any skill apart from programming, actually. I simply had to focus on projects that could sustain me (in the literal sense – bringing food to the table). I focused on simplistic open world multiplayer web games. Overengineering everything because while the games might be small, the dreams are big. I could write a few posts about all that on my blog, if I ever find the time. But we are talking about Fantasy Sphere here.

Short story shorter, I took over a year to create NextRealm Bubbles for my (very empty as of now) multiplayer web games portal Next Realm. Being more of tech demo than a good game (I hinted at this in the last devlog), I had to start working for other people instead of myself. While it is an experience in itself, it’s mostly boring and time wasting, and I’m anxious to get back to working on Next Realm, so I can get back to working on Fantasy Sphere.

Too many steps, you say? Alas, yes. Gotta fund the development somehow.

Pondering The Orb

So what’s the plan? Easy. Freelance to fund Next Realm. Get it off grounds, and use that to fund Fantasy Sphere. Then just work on Fantasy Sphere for the rest of my life.

What’s that? I should get real? Who said that? I demand you get in here, stand up and explain to the audience what you meant by that. It’s called Fantasy Sphere, after all.

In all seriousness. I don’t know when I will be working on Imagination Ball again. I do hope it will be sometimes later next year, i.e. 2022.

Shallow Ponder

Short-term, it currently looks quite likely that I will be able to return to work on Next Realm shortly. But I don’t know what opportunities might come knocking, so it’s not a guarantee.

I estimate about a year of focused work on that until it starts bringing in enough funds, so that I can dedicate proper time to Fantasy Sphere again. I would love to do it sooner though, if I manage.

Deep Ponder

I have been thinking of how to make all this a bit more tangible. And I found a way. What was described as the Town Of Dotfal in our website’s about page, could be expanded into something cozy, fun, slightly exciting, and mainly playable.

The idea is to finish the core minimum, walking around an empty town kind of thing. I would port to Phaser 4, integrate my multiplayer framework, and release it. Then keep working on it. Adding little features whenever I find the time. Evolving the engine. Hopefully with growing community (well, once there something worth playing, anyway).

What features might those be? NPCs going on about their day. Some fetch-quest story line. Interactive things like playing fetch with a dog (hey, we can already do that!). Multiplayer things like chat integration, account system, trading/crafting, playing football. Not entirely sure to be honest. The main goal would be to slowly grow it into a casual toy-like game, with features that are going to be useful for other games from Fantasy Sphere universe, or my Next Realm multiplayer games. Synergy.

There is really no timeline for this. But doing small features with the game being public should provide some extra motivation to find the odd hour here and there.

Thanks for reading, I wish you all nice holidays and a great new year. Until next time. :slight_smile:

Find out more about Fantasy Sphere.

2 Likes

Fantasy Sphere 2023 Status Report

Getting Smaller


Oh wow, did another year already went by? Things did happen this time around though, finally, so let’s talk about that. I promise to keep it short.

In the 2022 report I rambled about multiplayer experience as the next big thing in the Fantasy Sphere universe. That’s still planned, but was overtaken by something smaller and (hopefully) faster.

One of the best ways to get out of a rut and moving is to just start. Almost a decade ago I used the same principle to finally start working on an RPG. Earlier this year I’ve decided to have a go at it again, in the same spirit – just get something done, small, minimal, but an RPG.

Initially I’ve decided to spend an hour each day after work. That didn’t work very well as there’s never much extra energy left, and the hour was usually spent refocusing on whatever it is that I was actually doing. Not very efficient. So eventually I’ve switched it up to dedicating full Friday each week, and things finally started moving.

Introducing Fantasy Sphere Mini

While it’s all very early, and I am stubbornly creating loads of tech behind this, you can already “play” the game prototype. Not much you can do there for now. But hey, it’s something.

What will it be when it’s done? The smallest simplest RPG I can manage. And a start at all the tooling necessary to create one. Let’s hope I won’t over-engineer it all too much.

In the following months I will go back to writing devlogs. And who knows, maybe by next year we will have a tiny game to play.

Find out more about Fantasy Sphere.

1 Like