Technical challenges in map mode

For discussion of the code running behind the game

Moderator: Staff

User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Technical challenges in map mode

Postby Roots » Wed Jun 22, 2016 3:58 pm

Roots' wish list of programming/scripting features for use in map mode

Implemented
  • Notification Engine
  • Notifications on map sprite collisions
  • Smoother map context transitions
  • Track how many times each map event has been started on the map
  • Add additional map events for common map script operations: PushMapStateEvent, PopMapStateEvent, CameraMoveEvent, ChangePropertySpriteEvent
  • Improve our map sprite and enemy sprite creation shorthands in Lua
  • Have the editor state the coordinate boundaries of a selection area in the status bar when a selection is active
  • Add property that allow map sprites to display their walking animations even when standing still
  • Add property that flips the direction the sprite image is facing relative to the sprite's direction of movement (aka, "moonwalking") :cool:
  • Add simple state tracker in map mode (string/integer pairs) that can be set and read (now called "local record group")
  • Allow records to be written by starting map events, and by dialogue lines and options executing
  • Remove ChangeDirectionSpriteEvent class and replace all uses of it with ChangePropertySpriteEvent

Planning to implement "soon"
  • Move sound and music object storage to map scripts and stop relying on audio logic hard-coded into MapMode class
  • Remove or redesign ContextZones
  • Create notifications on every sprite position change; use this for ResidentZone class to automatically check when sprites are inside (instead of having to do it manually in the map script)
  • Dialogue property that instructs the sprite owning the dialogue to -not- face the player sprite when the dialogue is active
  • Add a second dialogue icon that displays only when a sprite has new, unread dialogue
  • Add SoundObjects to map code, which are invisible sound sources that can be placed on the map

Post 1.0.0 release
  • Blending one context into another during transitions
  • (Possibly) Refactor the way we store coordinates for objects (currently two int and float offset) with two floats
  • Rename map_sprites_stock.lua and possibly make it more generic and include other convenient Lua shorthands for making multiple C++ function calls



------- Original Post Below -------

As we've been building larger and more complex map, I've been finding several technical obstacles with scripting them. The purpose of this thread is to list these obstacles and point out other limitations of the map mode code, and then to discuss solutions to them.


Issue: map context drawing and switching
When you switch from one context to the next, the change is instant. It's a little jarring just walking through a door and suddenly being in a different "map" in a single frame. So we want to make the transition a little more natural. But there are problems with the way manage contexts right now. To figure out what context we should draw, we look at what context of the object that is being pointed to by the map camera. We get around this somewhat in the cave map by scripting a fade screen event to black, change the context, and then fade back.

There's already a task for improving this that I'm working on. Here's the changes I've got coming:
  • The current map context (the one drawn on the screen) is no longer always the context of the map camera. We now manage a member that tracks the active context, and to change it we call one of several functions for transitioning contexts.
  • There are three types of context transitions I'm creating. Instant (what we have now), Blend, and Color. Blend works by drawing two contexts on the screen at once, applying some transparency to the result, and blending the two images together. That way we can get a fade from one context into the next. Color does the transition by fading the screen to a certain color, then switching the active context, and then fading the color back out. You can also set the time it should take to complete the transition, or use the default time. I think Blend should be our default transition type.
  • ContextZones, which are currently used to change the context of objects walking through them, will mostly be unchanged. But we'll have to add some conditional logic so that the zone can detect if the player sprite is transitioning, and start a context transition if so. And we'll need to allow for some additional parameters so that the user can instruct the class what type of transition to do.
  • I considered making context transitions a type of map event, but decided it was simpler to just have the transition managed directly in the MapMode class rather than have to create and initialize a new event for every transition.

These changes should go live in the next few days. I'm open to suggestions or alternative approaches.


Issue: event triggers aren't comprehensive enough
The event system itself works wonderfully, but what I think needs improvement is the way we trigger events. The only way we have to do this right now is either in the map script's load function (starting an event right after the map finishes loading), or through a series of if statements in the script's update function. Usually those event checks are simply "is the player sprite inside any map zones that we defined?". In other words, events are only triggered by physically moving to a location on the map.

I'd like to be able to trigger events by other means, and perhaps have some better mechanisms for the existing way to trigger events. For example, if the user presses the confirm button while facing an interactable object, I want an event to be able to fire. Or if the player sprite collides with something, such as a locked door, I want to trigger an event (maybe play a "locked door" type sound). And maybe other conditions too, such as a check after battle to see if fatigue is high, and maybe have a character in the party warn the player that they are heavily fatigued.

I haven't gotten much further than defining what it is I'd like to be able to do at this point. I'm still thinking about how to actually go about making this happen, and what needs to change to support this kind of triggering system. I'll probably have to go do some research to figure it all out.
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Mon Jun 27, 2016 12:48 am

An update on the two topics I posted previously.

Context Switching
This is implemented and I'm working out the bugs. However, there's an issue with the blend transition in that I don't know how to do it. :heh: I thought there was a way in our video engine API to draw a bunch of images and apply effects (like modifying transparency) to the entire screen. The only way I've seen to do this with our current API would require saving the screen to a temporary image file, then drawing this image to the screen (this is how we draw the map mode background in menu mode, for instance). But creating, saving, and deleting a temporary image file for every frame just to do this transparency fade is way overkill.

For now, I'm just going to do color transparency. We can always add support for blend transparency at a later date.


Event Triggers
I've been doing some reading, asking, and thinking about this one. Still don't have a firm way I want to go, but here's some ideas.

1) Use the observer pattern

Basically we'd implement a mechanism that allows code to listen for events. When events happen, they register within this observer class and code that cares about those types of events detects it.

2) Lua function handlers

Here we'd define a few different Lua functions that are part of the map file for handling different events. For example, SpriteMoved, ObjectCollision, or CommandPressed. When the map code detects these occur, it calls the Lua script function with information about what just happened, and Lua figures out if we want to do anything as a result. I like this because its so simple, but I'm not sure if it's a good idea to be making so many function calls into Lua for every single change.

3) Trigger queue

This is a bit of an evolution of #2. Instead of having the events call a Lua function when they occur, instead they register an event in a queue maintained by map mode. In Lua when we run the update function, we go through the results of this queue and process all the changes that happened, and determine if any should trigger an event. This way we keep our calls between C++ and Lua at a minimum, and we have the added advantage of bulk processing of events, so for example if we want to make sure we don't do the same thing twice (ie, play a sound for a collision), it's easier to do this way.

The challenge with this one is how to preserve and present all the data in Lua. I thought maybe of using small data classes for each event type and determining dynamically which event it is and knowing what data is available to extract. But I wonder if this is really a better solution than #2. I'm still undecided. :|
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Wed Jun 29, 2016 3:51 am

Okay, after thinking about it more and seeing what another project has done, I think I have a general direction that I want to go.


I'll create a new class in the global code, something like GlobalTriggerManager that maintains a queue of GlobalTrigger objects (which can be sub-classed by various modes). On each update of the game loop, the manager keeps track of what triggers have been fired throughout the code on each game update, and discards them before the next loop begins. You register a trigger occurrence by calling the "Notify()" function on the manager and pass it your global trigger object. The update code for the various modes are responsible for going through the list, looking at the triggers and figuring out which ones it cares about, and acting accordingly.


The GlobalTrigger class is a light-weight abstract object. The class contains two strings: one identifying the category of code that fired the event ("map"), and the other identifying the type of event ("collision"). It is up to the sub-classes of GlobalTrigger to add other relevant data if necessary. Some events may not require any other data. But lets consider a map collision event, which may need to include: what type of collision occurred, which object(s) collided, and where the collision took place. The lua code can then examine the list, find collision triggers, and look at the objects and coordinates and take an appropriate action, such as playing a sound or switching a context.


The reasons why I think this is the right approach to take:

1) Triggers are something that are useful (and probably needed) in more than just map mode. Map mode has the most immediate need for this sort of functionality, but doing it there would just mean we would have to re-implement a similar system in other areas of the code, which is unnecessary.

2) Triggers from the global code can be useful as well. For example, consider adding a trigger for every time the amount of drunes change, or a character levels up. Using this, we could easily add an achievement system to the game if we wanted to and track things like "Savings of 5,000 drunes" or "Reached Level 20 with all characters". Not something we'll do anytime soon, but useful for the future.


There are two things I'm still thinking about though:

1) Maybe this trigger management code better belongs in the engine. Having it in the global code means that the engine is unable to fire triggers if it wants to (global code is not permitted to be included in the engine code). Maybe we want to have triggers for when the music stops playing, or when a screenshot is saved? I'm leaning toward sticking it in the engine just in case we might ever want to use triggers there. I can't really think of a reason not to, although it would require another engine manager class we'd have to use and throw around.

2) It's been a while and I forget how Lua handles dynamic object pointers. We can easily figure out what type of trigger class maps to the combination of the two trigger identifier strings, but I'll need to do some research and remind myself of how this stuff works.

------

I'm probably going to begin working on this trigger management code this weekend. Before then, I'll be committing the changes I made for context switching and management in map mode. That work isn't fully complete, but its working. I'll need triggers to fix the oddities with context zones.
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Thu Jun 30, 2016 2:53 pm

My map context transition code is now in the main repository. I've also completed the preliminary work on the notification engine, and you can view it here. Brief summary of what I did and what is yet to be done.

- I decided to use the nomenclature of "notifications" instead of "triggers" because it made more sense and is also more generic
- I made notifications as its own engine component, meaning that any code in the game except for utility code may create and view notifications.
- Notifications are stored in a simple class object (NotificationEvent) with only two strings as members. The strings serve as identifiers for the category (which namespace generated the notification) and the event (what happened that generated it)
- For notifications that need to pass along other information about the conditions/state/objects that caused the notification, the relevant area of code should create a subclass for that type of event and add those members that it needs. The type of notification event can be determined dynamically. (Note that code may have need for creating multiple different notification subclasses based on their needs, and this is perfectly okay).
- All notifications sent to the notification manager (a singleton object for the NotificationEngine class) are deleted in the main update loop immediately after the Update() call is made to the active game mode


It's pretty simple really, as it should be. No notifications are being generated right now, so that's the next step, to begin using this new functionality. I'm going to start with map collisions and test the following in order. Once this testing is done, notifications should be ready for regular use.

1) generate a simple notification when a collision happens
2) have a map script detect the notifications
3) create a sublcass for collision events and stick in extra data, such as the type of collision, object ID(s), and location
4) have the map script be able to recognize this type of event and pull out the extra subclass data
5) do something useful with the notification, such as recognize that the player sprite collided with a locked door and play a sound
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Sat Jul 02, 2016 5:47 am

Of the to-do list I ended my last post with, I've done everything except #5 (I've only used notifications for debug print statements thus far). I have notifications for collisions working, although there seems to be a bug in the collision code itself where a second collision always occurs due to the collision resolution not properly setting the position of the sprite. I think that for now this is okay, and I'll be opening up a bug for someone to take a look at fixing this in the future.

Another issue is the fact that a collision due to user input usually occurs on multiple sequential updates. For example, if I hold down the down key and run into a wall, a notification is generated on every update that the down key is still being pressed. Even if I only attempt to lightly tap the key, it still generates about 3 notifications because 3 updates occur between the time I press and release the key. What this means is we're going to have to be careful to not launch an event or take another action if we detect that the event/whatever is already in progress. (We don't want to play a new "collision" sound once for every update). So map scripts will have to be careful to use conditionals or some other state tracking to make sure this doesn't happen.


Roots wrote:2) It's been a while and I forget how Lua handles dynamic object pointers. We can easily figure out what type of trigger class maps to the combination of the two trigger identifier strings, but I'll need to do some research and remind myself of how this stuff works.


Good news about this. I did some testing tonight and verified that we can do RTTI of notification event classes in Lua by using the category and event strings to identify the class. Once you know what class you are working with, you can automatically use all the members and methods that were bound to the derived class. As an example, I created a derived class of NotificationEvent called MapCollisionNotificationEvent, and gave it a COLLISION_TYPE (enum) public member called collision_type. I bound the class to Lua and made the collision_type member a read-only variable.

Here's code from the map script that demonstrates how this works:

Code: Select all

   local index = 0;
   local notification = {};
   while (true) do
      notification = NotificationManager:GetNotificationEvent(index);
      if (notification == nil) then
         break;
      elseif (notification.category == "map" and notification.event == "collision") then
         print("This is a MapCollisionNotificationEvent with collision type: ", notification.collision_type);
      else
         print "This is a standard NotificationEvent object";
      end

      index = index + 1;
   end


Note that if I tried to print notification.collision_type on the standard event object as well, it would just say the value for that member is nil, and not generate a run-time error. So this is pretty great, since now we can easily figure out if we care about the notifications that are active and have access to all the bound members and methods for derived notification classes. That was the last technical barrier/uncertainty to overcome before being able to utilize the notification system to its full ability.
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Fri Jul 08, 2016 5:41 pm

The notification system has really eliminated a lot of barriers to development on the capital map. I've also made a number of other improvements and additions throughout the code to make map scripting easier. You can see everything in pull request #36. Here's a summary:

- You can now create SoundDescriptor and MusicDescriptor objects in Lua and operate on them. This is much better than doing the lazy way of calling AudioEngine::PlaySound, which we've been doing before.
- I added a history tracker to the event manager in map mode. It maintains a counter of how many times an event has been started. You can query the history of any event using its ID. Using this, you can implement a simple check to make sure that an event only happens once (previously you'd have to save a variable to the global event state to track this).
- Added a function to quickly check if a sprite is facing a given direction

Using these features along with the notification engine, I was able to make a "locked" sound play whenever the player collides with a door that they can't enter. On the first locked door, a dialogue also comes up that basically tells the player that all the doors in the city will be locked and that they shouldn't bother with them.

Future Changes
* Map Audio Management
Using the new audio engine bindings, I'd like to completely change how we think about audio management and playback in map mode. The old way of doing things was to have the map script define a list of audio files used on the map, then the map creates the audio descriptor objects, loads the files, and playback has to be managed through those objects. It's not flexible at all.

In the near future, I'm going to completely remove all audio from MapMode, and the scripts will instead need to define all their own audio loading and playback. I might leave in some shortcuts for convenience, like allowing a script to pass in a piece of music and tell map mode "keep playing this until I tell you otherwise", since a lot of maps will have a single looped music track.

* Context Zones
I'm going to either completely remove context zones or change their function significantly. Collision-based context transitions are a lot better and less error prone, and I just don't see a use for our traditional context zones anymore.

* Zone Resident Management
A ResidentZone class is one that keeps track of all the sprites currently inside it. I'm going to change this a bit to use the notification system, and have a notification sent out anytime a map object's context or position is changed.


I'm really enthusiastic about the direction that MapMode is evolving. :approve: Also, I have encountered several small bugs in map mode through my scripting progress on the capital map which I have and will be addressing as well.
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Thu Jul 14, 2016 5:44 am

I wanted to briefly summarize the work I've done in the last week, now available in pull request #37. In addition to further development on the capital map and map scripts, this included a lot of fixes and various improvements to make some common aspects of map scripting a little easier.

New Map Events
I added three new map events:
  • PushMapStateEvent
  • PopMapStateEvent
  • CameraMoveEvent

I found that all of these are operations that are needed across several maps (in fact, they are used in nearly every map so far). To implement these in the past we were creating CustomEvent classes and writing small functions to do the operation. Now you don't need to awkwardly define the functions and implement custom events. It's all done within a common event class. :approve:

Map Sprite Creation Improvements
In map_sprites_stock.lua (a filename which I totally want to rename at some point) we defined some functions that made it easy to setup all the common properties of a sprite in a single call. These were pretty inflexible though, especially with enemy sprite creation. These functions have been greatly improved both in their API and implementation (just take a look at the diff to see the details).

Map Editor Improvements
Two minor things I improved in the editor. First, the default selected tool now is the select area tool, not the paint tool. Having the paint tool selected on boot was kind of awkward, because it was too easy to accidentally click on the map that just loaded and make a change you didn't mean to. The select tool makes no changes, so it's safer to use.

The other thing was the status bar text. It used to only show you the coordinates on the map and the tile index that the cursor was pointing to. Now, if you have an area of the map selected as well, it tells you the min/max x/y of any tile in that selection. This is useful because it makes it much much easier to open up the editor, select an area that you want to make a zone (enemy spawn zone, a zone to trigger an event, whatever). I've already been using this a lot to aid in my map script development. It is a little bit buggy, but for the most part it works great.

----------

More Future Changes
There's a bug when going into a dialogue on a map where if the player sprite is in motion, it will stay in motion even as the dialogue is active. This needs to be fixed so that the player is stopped during a dialogue (unless its being moved by an event).

I want to add a feature to allow sprites to "walk in place" and make use of it on the capital map. It looks really awkward with sprites standing still next to one another while they are engaged in battle. There's no way we're going to have the time/resources to animate knights and demons fighting, so having them display their walk animation without moving is the best we can do (and I've seen this in other RPGs too, so its not without precedence). Maybe we can add a moonwalking feature too :heh: (walking animation is opposite to direction of movement). Probably not this release, but might be fun to have and use in the future.

Not sure if we already support this or not, but for certain situations where the player engages a dialogue with the sprite, we don't want the sprite to face the player. For example, the captain has dialogue while he is in battle with a sprite. We don't want the player to see him turn his back on the enemy to have a friendly little chat. :uhoh:

Finally, I think we need two dialogue icons. One for dialogue that is read, and one for unread. The reason being is that not all sprites in the game have dialogue, and the player has no way of knowing whether a sprite has something to say unless they have the new/unread dialogue indicator floating above their head. This should be pretty easy to implement, as well as create a variation graphic for the indicator.



That's all I have for now.
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Thu Jul 21, 2016 6:25 pm

I've found the need for another feature in map mode today. The issue is that we sometimes need the ability to track how many times something has occurred. For example, how many times the player has walked on a switch. If the switch triggers an event immediately, we can do this by checking how many times the event supervisor has started that event. But if the switch doesn't trigger an event, or it triggers an event after an initial delay, then we need something else.

That something else I'm calling the map data log. It works just like global events, in that it is simply a std::map with string/int32 pairs. The string is used as the identifier, and the int is a counter for whatever we'd like to track. The major difference between this and the global events is that global events are visible globally (imagine that) and when the user saves the game, that data is saved in the game file and restored on load. The map data log only retains the data until that MapMode instance is destroyed, and it is not kept on a permanent basis.

I'm adding this functionality to the event supervisor class, even though it's technically not a part of events (though will be often used together with them). I considered putting it in MapMode, but that class is already very large and I'd rather not keep bloating it. I'll have this featured implemented and operational on the capital map by the weekend.


Roots wrote:I want to add a feature to allow sprites to "walk in place" and make use of it on the capital map.


This is now implemented and active on the map in my public repository, and it looks great. All you need to activate it is to call sprite->SetStationaryMovement(true); Another thing I'm going to add is the ability to "moon walk". Essentially, face the opposite direction that you are moving. This way we can mimic sprites backing up while still facing a threat.
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Sun Jul 24, 2016 4:29 am

Doing some more scripting tonight and one thing I'm finding is that I often need to change one or more properties of one or more sprites in an event sequence. For example, their direction, their collision enabled property, their movement speed, etc. Every time I need to do this, I have to create a CustomSpriteEvent and then write a small Lua function at the bottom of the script file just to modify all these properties. And having what happens in an event defined in two different places is kind of messy.

This operation is common enough that I want to create a class to handle it. I'm calling it ChangePropertySpriteEvent, and it will have a variety of methods to indicate which properties should change when the event is fired. And for even more convenience, I'm going to allow the user to add multiple sprites to this event after its constructed (again with methods), so that way we can easily change the properties of all sprites instead of needing one event per sprite.

I noticed that there is already a ChangeDirectionSpriteEvent (that I most likely wrote) and it is in use in the first two maps of the game. I'm deprecating this class and it will eventually be completely removed and replaced with ChangePropertySpriteEvent. I'm writing the class tonight and plan to start using it immediately in the capital attack map. This should be pulled into the main repository and ready sometime next week.
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Mon Jul 25, 2016 4:57 am

Look back at the first post in this thread. This monologue (forever alone :heh: ) is serving as a record for my thoughts and plans as I continue finding obstacles in map scripting. It was becoming rather disorganized with stray thoughts everywhere, so I listed down everything I have done, want to do, or wish to do in the future to improve map mode. I'll keep this list updated every time I post here.


Tonight I implemented the "moonwalking" feature for sprites. It didn't take much work at all, and looks great. I added the ability to alter this property with the new ChangePropertySpriteEvent class as well. So that's another feature completed off my list.


I had a great idea tonight about something else I want to do. One thing that is very sorely missing from the capital attack map are sounds. We have the ability to play sounds through events, but I wanted to play environmental sounds based on the location of the camera. The audio engine should already support distance attenuation for sounds (we added it ages ago, but have never used it). So that's the desire.

I think the best way to implement this will be with a new type of MapObject called SoundSource (or something like that). Basically, a sound source is an invisible, uncollidable object on the map that plays a sound. When it plays it and how loud it plays it is determined by the object's Update function, which looks to see the distance that the camera is from the object. If it is too far, it will do nothing. If it's within hearing range, it will calculate how loud the sound should play. This class can additionally accept a property to affect the type of dropoff of the sound as it gets further away (the audio engine also supports this). And we can have an entire rectangular area of the map serve as a sound source, because if it was just a point that would seem odd (ie you could be in the middle of a large battle field, walk half a screen over, and the sound would be quieter even though you are still in the thick of it.

This is probably something that I'm not going to do right away as it will be a lot of work, but it is something I want to get in and make use of before 1.0.0 is released.
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Thu Jul 28, 2016 7:13 am

A couple more things I've been thinking about:

- I'm renaming the "KeyValueData" and data log that is stored in the EventSupervisor and instead calling them local records, as they mimic the same functionality that global records do. I might also decide to move this to the MapMode class after all, seeing as how it's just a handful of short methods that are disjoint from everything else map mode does.

- Dialogues can start events, but not set records (formerly known as global events). It's a common case that we would want to retain whether or not a player has read a particular dialogue or chose a particular option. I'm going to add some methods on MapDialogue that allow you to set records (both global ones and local ones stored in the EventSupervisor) to be set for dialogues.

- Likewise, I think it will be a common case that we want to set global or local records when a map event happens. I'm considering either adding a new event class that just sets the records and does nothing else, or possibly adding functionality to the base MapEvent class to indicate that the record should change a global or local record when it runs. I'm heavily leaning toward the latter, as its a lot easier as the user has a single method to call instead of having to create another event and link it into an event sequence appropriately.
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Sat Jul 30, 2016 6:29 pm

I've taken action on the items in my previous post (and updated the list in the top post accordingly). Here are the major changes.

MapMode now holds two CommonRecordGroup objects, one for the global records (those stored by the GlobalManager) and one for local records, that store temporary records that we toss away once the map terminates. Both of these objects are granted access in Lua.

MapEvents can now optionally add any number of global or local records they wish to set when the map event's _Start() function is called.

MapDialogues also can now set global and local records in one of two ways. You can either attach records to a line, and records will be written when that line ends. Or you can attach records to an option, and those records will be set when the player selects that option.


I'm already making use of this in the latest capital map scripting, and it's pretty easy to do. It simplifies a lot of logic in the scripts. In the process, I also refactored and cleaned up a lot of the map dialogue code, which was kind of messy. It's better now, but still could use a thorough look-through. But I'm back to focusing on scripting now that I have the functionality I need from dialogues.
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Tue Aug 02, 2016 12:26 pm

Quick update on what I'm working on. I've noticed several issues with path finding/path movement that, while I can find workarounds, make certain things difficult to do. Specifically I've noticed the following.


1) Pathfinding fails due to object collisions
I've actually already got a fix for this one pulled into the central repo. The issue is when we're computing a path for a sprite from A->B, if there's a sprite or other object in the way, the path finding fails because it can't find a way around it. This was making it impossible to do certain scenes like showing a demon chasing after a NPC. The solution I implemented was to just ignore object collisions completely in pathfinding.

This will probably be something we need to re-visit at some point in the distant future, but for now this works.


2) Collision detection fails on alignment with grid boundaries

If I have a sprite with a collision rectangle where the bottom is currently 26.0, the collision code actually examines the grid elements -below- the sprite collision rectangle. This is because we simply cast the float to an integer, so 26.0 becomes 26, and that y position is the grid element below the bottom. This should be a pretty simple fix. And this will then allow us to move sprites on a path with a destination that lies on a grid boundary.


3) Path movement doesn't allow setting of offsets or exact relative movement.

When a sprite moves on a path, it considers its movement complete as soon as its origin coordinate (it's bottom-center position) is located within the destination integer coordinates (ie, 14x, 20y). The problem is that depending on the direction the sprite is coming from to reach those coordinates, their actual position can be very different. It could be 14.05x, 20.0y. Or 14.95x, 20.87 y. So currently, we have no way to move a sprite to an absolute position, and only put it "approximately near" the destination. We also don't have a way to specify any offset in the destination, like if I wanted the sprite to reach 14.5x and 20.7y exactly.

Fixing this is going to take some work in multiple places in the code. The pathfinding will have to be able to check these offset coordinates on the destination to ensure a sprite can rest there. And the path move sprite event is going to have to handle the "offset" part of the movement to get the sprite in the exact position.



I hope both (2) and (3) fixed this week. One fallout from this though is that the existing maps using path finding might need tweaks and adjustments if the new "precise" path messes up coordinates and offsets.
Image
User avatar
Roots
Dictator
Posts: 8666
Joined: Wed Jun 16, 2004 6:07 pm
Location: Austin TX
Contact:

Re: Technical challenges in map mode

Postby Roots » Tue Aug 09, 2016 4:00 am

I've got a fix committed for (2) from the above post now. I decided to hold off on (3) because it will be a lot of work and testing. (3) is more of a "would be nice to have, but can make due without for now" anyway and I need to stop getting bogged down by addressing all these various issues in map mode so I can actually focus on creating the map scripts. :heh: So I made a task for it in the issue tracker and my hope is that someone else might be interested in taking a stab at it.


In unrelated news, I had to cut back a bit on the amount of time I was spending on Allacrost in the last week or so. Things at my job have gotten a little hectic and are requiring a bit more from me lately. Plus I could tell that continuing at my former pace was going to lead me to burn out eventually. i'll still be active of course, just probably working at 50% of what I have been for the last month for a while.
Image

Return to “Programming”

Who is online

Users browsing this forum: No registered users and 4 guests