Search Unity

Discussion Character ai, code architecture

Discussion in 'General Discussion' started by neoshaman, Feb 23, 2023.

Thread Status:
Not open for further replies.
  1. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    I posted the questions originally on script, but I noticed open ended architecture questions seems to have more luck here.

    I have been experimenting for a long time with various pattern for making complex characters simulation that would work with simulated story. And I mean I read everything I could about the literature, from Alex j chapendard (aigamedev site, killzone ai programmer) to Mark Dave and Kevin Mill ( popularizing utility ai in game, worked on the sims). I'm name droppings people so you know I did diligence.

    The problem is that the usual pattern were highly unsatisfying and didn't reach the right balance of control and flexibility. Over time I evolve to a kind of ai sandwich that takes the best lesson of all of them. With a world blackboard that is queried by a utility tree that match to perceptual concepts instead of actions, an if tree that select state variables, and states machine for the actions. The game is similar to yandere simulator meet Buffy the last vampire. That is a mix of reactive ai, with persistent named character with unique behavior and top down directions for situations, using time table.

    That's the context.

    It works pretty great, except one single things. And that's where I have architecture problems.

    The main issue is in the BT like structure. I have issue make variations for each character without resorting to have a single tree for all character.

    A regular BT only run one action at a time, actions opt out a node on fail or success, and all actions are on leaf. That was too rigid, so I just used the pattern (sequence and priority) to organize the code. That mean I have actions that can run at every level of the hierarchy, which allows pre processing for further actions down the tree, and many actions don't opt out a node entirely (typically called concurrency in BT), that was the key that allowed the structure to maintain flexibility and authorship.

    The benefit is that, on the current form, it's KISS and KILL. IDE has collapsing blocks ui, which allows the code to be neatly organized like folder with if blocks. Reading, editing and debugging has never been easier given the power afforded. Even if a block go up to hundreds of line, I can just copy paste by collapsing first, even in the most simple IDE. When there is an error I get send to the exact line, and just walking the hierarchy I have all the context needed. When I tried breaking the tree into subtree and method, that was useless, because it just shifted the complexity to the file folder without any benefit, and if I keep it in a single file, the node method list became ridiculously long and impossible to navigate, while obfuscating the logic.

    Now the problem is that, if I want to override a node to make varients per character, I no longer have a flat method list to selectively replace. At least without ruining the neat workflow.

    The core of the problem is that currently, I have a generic tree, with tons of exception rules for named character.

    I would want to move the named character exception in their own file. The problem is that they are by the nature of the domain, all over the tree and I wasn't able to generalize. There two main pattern of occurrences. Insertion and inhibition, basically the equivalent of adding a check in the node for if ischaracter(name) or !ischaracter(name).

    In some way we can see the structure as a metaphore of cards. Each card has a check and a list of actions, but cards being type of actions themselves, they can be nested forming the tree. Inhibitions and Insertion lead to substitution or replacement of cards. A card is said to be substituted if we modify the actions list but not the hierarchy (we don't replace card in the list of action), replacement is when we switch the card and the whole hierarchy.

    What I want is to find a way to have a generic tree of behavior, but selectively override cards anywhere in the hierarchy, such that I don't need to duplicate the tree, and thus don't pay the cost of updating every hundreds of character. Like amending the generic tree with a different masking of variants cards.

    Is there a design pattern that allows to do something similar?
     
  2. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    Most likely it would be better to have the same BT for all characters. It will be less work than maintaining hundreds of different trees.

    Also, when you copy-paste, you're shooting yourself in a foot. With a nuclear grenade launcher. If the block you copied had a bug, and you fixed it in one place, good luck tracking all places where you copied it. It is an extremely bad idea.

    You need to break down trees into components. There are going to be patterns, and all characters will end up following same general patterns. For example, top level tree could be something like "If patrol is set, then patrol, otherwise idle", where "patrol" would be "follow patrol route unless enemy spotted then pursue" and "idle" would be "stay in one lace unless enemy spotted then pursue". Here you're seeing how a reusable subroutines emerge.

    In situations where you need to override part of the behavior, you make it into a pluggable module with parameters or configuration. For example, all characters can have "combat" module, but how exactly they fight could depend on general archetypes. Or you could make one combat module for all archetypes. Then you can introduce personality stats like bravery, agression, etc, which would affect likelyhood of an action being chosen.

    So, basically you most likely need to continue that path you ignored.
    Single trees for all characters, parameters for characters that override likelyhood of actions, modules that can be plugged into the trees, and splitting long files into smaller ones.

    Copy pasting is bad, long methods are bad, huge files are bad, code behaviors organized into subfolders are good. "bad" because they corrupt your codebase, makes it harder to maintain it and prolong development time.
     
  3. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    I knew this would have a comment, I did shoot myself in the foot there lol. It wasn't meant to be interpreted literally, just to highlight how easy I can manipulate the tree, in practice I never have to do that, because the thing with these kind of tree is that each branch is ordered and specialized, even when refactoring I barely touch the hierarchy, I just prune redondance. It's just that maintaining a tool to do the same is more costly and scary.

    That's true for a typical game, but I'm closer to a story simulation, those behavior would be the generic tree. But what I need is the extra behavior that makes a named character unique, it goes way beyond adding "adverb" to actions, you want whole complex acting specific to that character not shared with other, and that goes beyond having different animation.

    I'm trying to cross into place I don't think other game has made yet at that scale. Most game just have a few complex companions character like in final fantasy, bioshock infinite, last of us, in which having a unique specific tree (and a large team to populate it) is okay. Imagine I'm making (a uglier, stiffer) game where all NPC have the complexity of companions (social simulation).

    I have the concept of persona as general archetype
    (stolen from Yandere simulator anyway) to try and reign some commonality for group of character, that wasn't enough, and just created some more exceptions, except that instead of having extra test for unique character, I also have exceptions for groups of character too. And even the persona are polluted by per character override anyway.

    Basically what I need, is more than modulation of generic behavior, that is the ACTING and QUIRKS of character, that's part of the need for staging that makes your character be simulated character and not mindless NPC. I did my best to make everything composable and modular where I could, finding a way to turn "quirks and acting" into module is the reason I'm asking for help.

    The problem is that, currently, if a character is removed, it still has its footprint all other the place. Heck sometimes just modifying the character entirely personality mean touching all around the code. I'm still trying to find clever way to generalize, hence why I asked if experienced programmers had something that solve a similar problem.

    But if that's your conclusion, maybe I chew a bit too much and I have to swallow the pills. There will be like hundreds of character. For now I stay close to the yandere simulator concept for learning, but I intended to expend on a real project after I sought out to figure out the basics.

    I'm still refactoring the tree, maybe I'll come up with some more ideas. I also have the issues of specific to specific character interaction (like two specific brothers having a unique bond) that I have studied properly yet (just hardcoded). I need to contained the specificity from spilling. I want composability while keeping it legible, if that's ever possible.

    So what you say is exactly what I'm trying to achieve, a singular GENERIC tree for all character, and character only implement override that are specific to them. The issues is the nature of the override.

    Most of my project who failed, is because I was starting to get lost into too many file and couldn't follow the ai logic anymore. While I agree in principle and understand the idea, my former prototype died because of that. But that's specific to this very problem, for other things that work great because the logic is highly decoupled due to the domain, and generally you have kinda flat-ish local architecture.

    And I have already liberally modularize the AI into more module than most, the Perception module completely abstract the checks from the decision selections and decision don't even fire actions, generally people use the same structure for all. So my problem is highly contained in a single domain: the decision module.

    AND i'm precisely asking how to make MORE modular
    (separate generic logic to specific logic). I highlighted the decision to go on an if tree to explain the current situation, what it solved and what are the short coming, and I'm asking for a model to go beyond the short coming (entanglement of generic and specific in a tree), if that model exist. The model is amazing when designing a single character, but increasing the scope is the problem.

    Maybe I need to restate the problem:

    I have a powerful tree structure, that allow to do complex behavior effortlessly, BUT where generic logic and specific logic are superposed, I want to find a way to detangle them such that specifics goes into their own file, turning the whole thing more modular.
     
  4. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,694
    Maybe modularize this further, using some kind of subsumption architecture, along the lines of what Alex Champandard called layered simple FSMs, or what Igor Borovikov calls an Orwellian approach to AI architecture. This should work well for characters with strong personalities because you can add different layers to different characters that take control under specific circumstances. For example, take an NPC that has an OCD compulsion to count steps when approaching a staircase. You could add a layer that takes control whenever the NPC approaches a staircase that makes it count the steps. Or say you have a fantasy NPC elf that hates orcs. Add a layer that subsumes control whenever it encounters an orc, and causes it to go into a murderous rage. This way you can build complex behavior out of smaller but interesting building blocks.
     
    MadeFromPolygons and neginfinity like this.
  5. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,770
    Tons of text here, I read it mostly. But scanning quickly I could miss some points.

    My proposal is to add Utility AI to the mixture. It will provide some form of randomness feeling, while keeping realitively simple, and generic. You could have some value modificator per each AI character, which makes behaviours variants, without changing BT or AI Utility structure. Try to give your AI some urges. So they bahavioir varies, even depending on envirement they are in.
     
  6. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    In practice, you should never CONSIDER doing that. It is a major no-no. DRY is not a "nearly absolute" principle (like KISS) but it is a good one, and for a reason.

    Making a character feel unique does not require unique behavior trees, only parameters. Because feelings happen in players head, not in code. Their uniques will be to much greater degree affected with their animation, voice acting (if present), spoken lines and so on.

    If you're making something akin Space Quest game, which is entirely story driven, then in this sort of game did not have any AI in first place, and only had minigames. Likewise, dating sims do not use a complex approach. It is all triggers, smoke and mirrors, and the BT is dumb as a brick. And it works.

    If nobody used this approach before, then you should expect your attempt to fail. If nobody has ever made it to this scale, it is highly likely indicating that it is not necessary or too expensive. And we're talking about companies that can burn half a billion on a videogame. Other people exist, they had the same ideas, sometimes 20 years ago.

    Those games do not feature complex companions. A companion in this sort of title is a brainless walking manikin follower and illusion of personality is created through scripted interaction, cutscenes and voiced lines.

    Have you played sims? Because the ultimate social game at the moment would be Sims. The characters are user-creaqted and randomly generated. They have universal tree for all, and that incorporates all possible behaviors. Similar approach is used in Crusader Kings, which, instead is based on situations, where a situation describes all possible choices for all possible traits.

    Character archetype is usually implemented as a parameter set for the universal tree and few swapped out text lines. Maybe some animations.

    See Sims. Right now you're definitely being sidetracked.

    A character is a stat block, which determine part of the character behavior.
    In your decision tree for every situation where a choice is made, you implement checks that accomodate behavior.
    For example, you have a scene where charactrer faces a closed door. You verify the stats and check how they open it. Lockpick, break it, or become depressed and cancel current task.
    On top of stat block, a character can have traits. For example, in some sims series there was "Evil" trait. That makes character cackle randomly. That means, that Evil trait rides along with background AI and fires randomly. That can be implemented in many ways, for example, Command pattern, Strategy pattern, etc.

    Then when something bad happens, the evil sim receives positive mood boost and gloats at the situation. This is done by the script that fires situation, - checks surrounding npcs and causes those with evil trait receive positive boost and play an animation.

    If we take dating sims, then there characters have no AI at all, and instead a basic scripts checks variables set by player choices, or unlocked by specific actions.

    Every social interaction in a social game is a lie, which is supposed to invoke feelings in the player. You don't need to emulate the actual relationship, you need to reduce it to workable pieces.

    Crusader Kings and Sims did it well enough. And if you're talking about "Amazingly convincing companions", then in my whole life I haven't seen one. It is always smoke and mirrors, stepping into scripts and triggering cutscenes. And implementing multiple personalities means implementing a trigger that gives different voice lines for the follower, depending on which personality stepped into it.

    Given that yandere simulator died, I wouldn't use its systems as an inspiration. It is possible that developer was heading to a dead end.

    That is a trial you have to overcome. While learning to program, there's an important barrier, which I call 100 kilobyte barrier. As long as your program is smaller than 100...200 kilobytes, you can comfortably keep it in your mind and program with ease. When it grows beyond that size, you can no longer do so, and difficulty suddenly explodes. Then it becomes important to follow rules (KISS + YAGNI are good), organize your files, split it into manageable chunks and so on. You only learn this through practice.

    That is highly doubtful. I understand that it is how you FEEL, but it is likely t hat you've coded yourself into a corner, and it is possible to scrap 80% of your code while achieving desired behavior. It is also highly likely that your conclusion that "it is all in decision module" is incorrect, and instead you've built an unsuitable model.

    It is as I said.

    * Play Sims and Crusader Kings. Take notes.
    * Start with high level logic.
    * Same tree for all characters.
    * Quirks can be implemented like Sims traits.
    * Personality is stat blocks.
    * You do not need to emulate a mind, only to fool players.
    * Characters are not sacred, and non-working approaches can be discarded
    * If you're stuck for long, take step back, use rubber ducking. It is possible that you'll need to redo everything.
    * Decisions can be handled not by the AI but events the script that fires events and checks for stats and traits, like an RPG game.
    * The situations have encoded all possible consequences for all stats and traits, when necessary.
    * Animations and voice lines matter more than AI. Write a different dialogue, and player's mind will see a different person, even AI is the same. A talking doll with zero AI and no behavior can be very convincing.

    For more detailed advice, someone would need to check your entire project in person. To see where you led the project, and where you would get stuck.

    And that would take days and would require hourly pay.

    -----

    Also one good reason to use same tree for all is because improving it will improve all characters. And in case of unique trees you'll have multiple characters with vastly different quality.
     
    Last edited: Feb 23, 2023
  7. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    @neoshaman, the issue here is that your question is both too broad and too specific, and to answer it, one would need to immerse themselves into your codebase for a couple of days and see which eldritch ideas has led you to the current state of affairs. Because the answer relies on your code architecture and people on forum don't see it, and you won't be able to provide the idea without hours of explanation. This is a typical scenario for "beyond beginner" questions, so welcome to the club.

    For you it would be far easier to get useful info, if you provided a specific situation which causes you implementation issues without referencing your architecture which people do not know.
    Also see: http://www.sscce.org/

    Otherwise you could just discuss this with chatgpt, I believe it still hasn't been completely lobotimized, and as long as you can fit the conversation in one screen of text or so, it might provide an answer before forgetting what it was discussing.

    Regarding AI, really, see Sims and Crusader Kings and how they split story in a modular and extensible way.
     
  8. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    @neginfinity you are wrong about the design, crusader king and the sims are bad for what I want, their character are too generic and rely on player imagination, and yes I'm closer to the scripted character on the reactive side, I said acting you interpreted as mind, you are wrong. I tried all of what you said already. It's all about authored simulation like façade by Mateas.

    The intended behavior isn't an issue and it's working as intended, I provided detailed for context.

    The issue is entirely architectural.

    Maybe it's not solveable in an easy way. Basically the tree structure is a highly ordered first class semantic. Breaking it to much hinder legibility and edition. Like using goto induce errors by jumping randomly in the code, turning the tree into a flat list of unordered functions or class obfuscate the semantic. After posting o tried again and was hit with instant regret. The alternative probably mean having to create and maintain a tool, but this is low level enough that's akin to creating my own scripting language, with the issue of having r&d on ui... that feels above my pay grade and skill.

    Also yandere simulator isn't dead, he released a full game in the form of the 1980 mode, and works on polishing the high quality version with animation, graphics, bug fix and voice acting. Head to his WordPress blog for the latest dev. The game is still trending strong on YouTube, though it's past the peak, it has a nice plateau.

    Yandere simulator is a reference because the only game that do anything remotely as complex are text based game like overboard by inkle, and ultimately I want to bridge the gap between innovation from these two form, 3d characters scripted simulation and complex characters interactions like in modern IF like versu.

    @TonyLi oh good catch, I need to look at them again. I kind of forgot what they were.
     
  9. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    I finished consulting the links. I was aware of these and used ideas adaptated from them, from the vague memory I had. Refreshing on their subject was very useful.

    I'll probably need to take second look at subsumption, I feel like that when I mentioned concurrency in BT like if tree, I'm having something similar. Coming back to subsumption will probably help make the implicit idea more explicit, by finding way to formalize the structure, and eventually separate it. That's a good find. Thanks.

    The perception model is not a sophisticated knowledge fact world modelling system, it's still just a bundling of stimuli model, just packing complex checks into readable variables, to make the decision part more readable, as pre processing. The UT part is mostly a stub for later, if I need it, I barely have any weighting, at least so far. It's just the formalism.

    Memory itself is just handled by switching state, relative to the gameplay perception. A character, for example, changing to a spiteful persona, is akin of him knowing you did something to him, but it's implicit rather than explicit, there is no reasoning. I plan to add the ortony and PAD model, but as a similar reactive model instead of an academic approach to agent. State modeling allows for authorship. I did a lot of work on studying implicit memory usefulness for these kind of games.

    I definitely have a form of Orwellian structure. I barely spoke about it, but the world state is a bit more than a dumb blackboard. It manages and tracks npc, objects and the player. Npc can't do anything without it, the goal are implemented at that level, which allows for authorship on a broad level, coordinating npc. For example it handles noc routine goals, patrol routes and activity slot assignments, occupency, overall states like gloominess, and time-date sensitive states like festival and other occurrences. Even what I called hard-coded, has layer of abstraction, it's hard-coded in the sense it only exist FOR these characters, technically you could slot other characters but that would be weird.

    But the key insight was accidental, I was mostly focused on hooking behavior on the tree, but a better idea would be to have the basic tree send signal at relevant node, such as the character intercepts the node ID and if it has a variant, execute it instead of the default. Which mean I get to keep the hierarchy and just wrap the body of the node. Let's see how that pans out practically and how to implement it.

    Thanks.
     
    Last edited: Feb 24, 2023
  10. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    No, I'm not wrong.

    Either you break it down into events that check every feat (like crusader kings/sims did it), or you abandon idea of AI interactions and strictly script every single interaction, then you'll get no AI, and your characters will rely entirely on writing, like a visual novel. There's no other way, really.

    There's no other way, because we do not have capacity to make a westworld. As a result, we have to either have full control over an actor (visual novel approach), or give just enough pieces for the player to imagine (sims/crusader kings). A frequent approach is to use dumb AI for making character walk around, then you litter triggers around which make it look alive. The trigger triggers cutscenes, one liners, animations. Making player brain do the heavy lifting is very efficient. See Kenshi, for example, and the "beep" npc.

    It is not supposed to be a "flat list of undordered functions". The "function" can be another tree. "If X then combat". "combat" can be a tree, a subroutine, etc. Being a subroutine makes it reusable. There can also be more than one "combat' subtree and can pass the one you want as a parameter, and that will get you modularized/extensible behavior. You can also move away from trees to coroutines, though those are harder to visualize. Multiple trees can also run in parallel.

    I'm not interested. There was some drama, and based on pieces of information floating about looked like the dev wasn't very competent at programming and had ego issues. Seems like the case of "a good idea can fall into wrong hands", which is unfortunate, but happens often.

    Lastly it is highly doubtful that "this is the only game doing it". It is more likely that you're unaware of other attempts. Japanese had a ton of experimental stuff among their visual novel hybrids and there's highly likely that one of t hem already attempted whatever this is you're trying to do, except it was probbaly also bundled with some sort of nightmare fetish fuel, as usual. Here's a tiny list of games with social simulation games:
    https://en.wikipedia.org/wiki/Social_simulation_game (That actually reminds me that I should try Ultima Ratio Regum at some point).

    ---

    Anyway, general advice:
    * You'll get better responses with focused bite-sized questions. The current queries you post require deep immersion into your project and this soft of thing requires a long term paid assistant that spent a month or two with your codebase, not a forum passerby.
    * The general tone indicates that you're likely bewitched by an "amazing idea (tm)"(which refers to a fascinating problem that wastes ton of your time and produces nothing) and are heading into a dangerous direction, where you can spend a decade of your life on your project and produce nothing in the end. Basically, being sure that "my approach is right" and "nobody attempted this before" is a huge warning sign that something may be very wrong. Billions of people live and lived on the planet, and typically no matter what you do, someone attempted exact same thing before.
     
    Last edited: Feb 24, 2023
    r9shackleford likes this.
  11. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    You are still wrong, because it's working right now, and not conjoncture nor it is your fantasm of ai. I'm very familiar with ultima ratio regum as I have exchanged with the author since before the game was programmed, it's on tigsource. And it's no surprise to me you prefer rumor to going to the source, about yandere simulator, I did my due diligence.

    Anyway Tony li was of great help. I no longer need to respond here
     
  12. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    Whatever, dude. Your life, your choices, your consequences to deal with.
     
    Last edited: Feb 24, 2023
    r9shackleford likes this.
  13. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    I've been moving all of my projects architecture to an ECS inspired design. It's not real true ECS (like at the low level) but the general architecture is like this:

    Logic is handled by Systems. Systems only execute logic, they do not store any state.
    State is stored in Components. All components are is a database really. No moving parts.
    virtually anything that exist in the world all belong to a single class (the entity, or gameobject). It's pretty much empty. It's just a husk so we have a thing to point to in the world.

    This has helped me dramatically improve code maintainability and ease of understanding. Because I no longer have any questions about class responsibilities or communication methods. It's always exactly the same pattern and so far, it seems to work without caveats for every situation I've faced.

    Data flow follows these basic rules:

    Systems read/write to components.

    If System ever needs to communicate with another System, a special component for storing system state is used. Practically speaking, its no different from the Components (used to store entity state), but I call it a System State Component, just for distinction.

    All events in the world pass to a central aggregator (I call it the Event Relay), which any System can listen to. This means that no systems ever know about each other. It also means that you don't have to ever think about who should talk to who. If something important happens, just pass to the relay and forget it.

    I've used this architecture for a survival game and a game that is similar in architecture to racing games. In the near future I'll be prototyping some more action oriented games with it as well, so I'll give it a go with more action oriented, goal driven AI.

    But I used it for some animal AI in survival game and it was great. I didn't need to use behavior tree, state machine, or anything different from the same architecture I am using for virtually everything else ( i mean everything, no exceptions).

    The benefit is that virtually all code in the project follows same pattern, so less cognitive load for the solo developer. I think that's important thing to keep a reign on, assuming you will also need to put energy into things like developing art pipelines, marketing, design, etc.

    There is other benefits, especially for collaboration and modularity, but that's not the discussion here, I only mention it in case it sounded like there is a detriment on those fronts.

    I haven't used this for complex or unique AI. Just adding because there was some questions about general architectures and problems with code maintainability, and this has been my biggest advancement lately towards those goals.
     
    Antypodish and ippdev like this.
  14. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    I do make sure that I will be able to evolve to such system later, teh whole point is to break the system into modular part that are sufficiently independent that I could run them separately and with var size that fit a cache. For example running the perception system on all data ll at once since it's separated from the decision.

    BUT the issues wasn't that the ai is complex, it's more like it's a "narrativist AI", and that mean a lot of exceptions by default, and in order to run this type of code as system, you better find a way to separate the exception from the generic which can be use in a system, especially that in general, you will have a lot more background character running generic code, that named character running specifics but only at certain time. @TonyLi Proposing a Subsumption architecture for example allowed to see there was a lot of factorisation to be have in the code, which would help contain some exception out of the system.

    That's assuming it doesn't work, but like I said, it already does, that's in the past, zero speculation, the problem asked is on the code management not the behavior. :rolleyes:

    AND ON TOP OF THAT, you are obviously a simulationist, you don't want to see beyond it other approach, like narrativist's way, which mean you are forcing ideas, I didn't ask for, into a framework that's fundamentally different from the one described.

    Simulationist is all about the chaos as story, every agents pursue actively its own agenda and story occasionally emerged from it, it generally need a high level overview of story to extract the good bit, which is why shadow of mordor had to have an interface dedicated to showing shifting alliance and balance of power. And why the best example pointed by simulation are spreadsheet game. The metric of quality for a simulation is the depth and fidelity of the simulation, everything else is irrelevant. That's great, but that's not the only quality to pursue.

    Narrativist is about the presentation layer and authorship, which simulationisty game lack. The quality is known as "well formed story". As such Narrativist aren't trying to simulate word with competing agent, but simulate the story space of meaning, plotting, stakes and character functions working toward the "well formed story".

    As such narrativist see simulation as herding cat and created the concept of the "drama manager" that instruct agent which role they play. Looking back, the simplest drama manager is probably a schedule table, character have goal based on the time of day rather than deciding from internal characteristic. The table can be anything such as an atmosphere level, the story progression state, etc ... agent implementing and selecting reactive behavior contextual to the goal specified in the table based on their traits (persona in my case).

    Drama manager can be more complex and reason or react on the state of the world, to implement authored story beat, by adding, removing or shifting role of agents. Like an RTS ai but dealing with "well formed story" as a goal. Generally you will have a background simulation, that is stable because of the table, and the player perturbing the stability, and pushing the story world to new state, forming a new plausible story. That is the story emerge from and around the player's actions, which mean it doesn't need an extra spreadsheet to extract a story. It's the concept of elastic story, it's a akin to blended animation tree applied to story.

    Also you are wrong when you say it hasn't been done before, but I'm not sure you want a history lesson on the various implementations, just gonna say you could have least study the list of social simulation you send me, Yandere simulator is an evolution (direct inspiration) from Tokimeki memorial, it also have elements from façade, versu, and Bethesda's radiant ai.

    The reason I'm cloning it, is to find where I could tacked on other model (especially conversation) to make it more complete. The reason why I try to separate architecturally the generic behavior and the specific behavior, is to have a structure more like versu's (character file and genre file, story file is already there in the form of the global agent manager) but 3d.

    The reason it worked is not because the dev is smarter than anyone else, but because the format of gameplay is ideal to make the case, it has unity of actions, unity of place and unity time. It all happen in a single place, the schools, where all characters stay the same and has low variability (students and teacher). That mean, that unlike RPG, you have high frequency interactions with the same sets and class of character, it has density.

    RPG have lots of character class you only meet transiently, spread over a large world, with complex technical requirement like LOD that doesn't allow them to be simulated at all time, that mean efforts is spread horizontally, and (story/world) states aren't correctly conveyed. Smaller game like versu and overboard, have issues with high surface of input (the entire language), that cover a surface of actions too big to be adressed correctly, and have even more class of character with all character being unique.

    Yandere simulator strike the nice balance between complexity and scope to surface a working structure we can expend from. And like I said the format it has did help a lot, it has generic character lift from anime tropes, which mean they are readily legible, you don't have to guess their personality and actions, making them perfect illustration for the implementations. It has a hierarchy of importances between agents, with regular school kids, teacher and rival, who have different roles in the story world, with regular students as background, being both obstacles and resources.

    The actions is entirely contextual on the social space, every action is significant, crouching in the corridor makes you suspicious, being at a place at the wrong time have consequences, holding objects at different time mean different things, and the generic settings makes it legible, it makes sense to not run with a mop during lunchtime, and during clean time nobody will ask you why you hold plastic bag.

    Even doing nothing have a consequences in the stakes of the story world, and the progression is handled by simply switching simulation state (like school in high alert, where camera is placed, students acting distrustful, happy go lucky photography club improvising themselves as detective, all base on a mix of generic behavior and specific behavior selected by the general agent manager). And how you act will be tested against you in the ending trial, so all actions taken will come back in a reverse detective sequence in which you try to prove your innocence, which integrate further the notion of "well formed story".

    I learned a lot studying it, and I believe we can perfect the lesson learned. We can make more complex story and more complex character and not leave everything to dialog tree. That is a game in which you ACT, that is visual medium have "show don't tell", gamist will told you "do don't show", and this will open the case for "BE don't do".

    It act as a working missing link between various implementation, and the thing that interest me, it's not a text heavy solution created around conversation, but a 3d world like regular games in which you communicate with direct actions, which allow to generalize the model and bridge the gap with common actions gameplay. Basically it allows to conceptualize how to port a model like Versu toward game like mass effects. Also I got my first job in the AAA industry based on my expertise on that domain. ;)

    I hope it's more clear now.

    EDIT:
    Recommended reading: https://emshort.blog/2015/05/24/framed-invisible-parties-and-the-world-plot-interface
     
    Last edited: Feb 26, 2023
  15. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    Like I said, that's not my problem. It is YOUR pet project.

    To say anything more specific about it, I'd need to dive into it, for a dive I'd need code and not walls of text, plus I'm not being paid for that. If you have specific question you can wrap into a few paragraphs and an example (see SSCCE), I can answer that.

    "your life, your choices, your consequences" simply means that you're going to bear all consequences of your decisions whether those are going to be negative or positive. You sacrifice your time for a novel approach, and it works? Good for you. It didn't work out? Well, tough luck. It seems to be working now, but is there a chance of a show stoper down the road? Of COURSE there is a chance. Is there a chance that you're onto something? Of course! Nobody really knows how large those chances are though.

    Straying away from obvious solution and trying something that nobody is using despite having ability to burn space program level budget on a videogame, might indicate that your approach has been tried, failed, and you're chasing blue bird of happiness. I've seen such people before. For example, I knew a guy who had spent 20 years of his life studying overtones. Not sure if it worked out for him. He was one heck of an oddball.

    Either way, your reasons do not matter for ME, because it is YOUR project, and your decisions, so you're the one who need to evaluate if the reasons are sound. I've said what I think and deemed useful, past that point, it is not my concern. So there's no point in trying to prove me anything.
     
  16. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    I think you have to find ways to generalize it all. I mean, how many different reactions can a character have?

    It might help to literally enumerate everything out so you can actually see what you are dealing with.

    For example, a person can talk, go somewhere, pick something up, go engage a conversation with someone else, go punch someone in the nose.... what else? All these different actions could really boil down to just like 2 or three. Travel to a destination. Start an action. Start a targeted action (e.g. an interaction).

    I mean, there just couldn't be that many things that can happen that can be generalized to a handful of basic actions, and within those actions to get the specific flavor you just lookup from a dataset, right?

    I think that if you cannot explain what you want to do so simple that a little kid could understand, it probably indicates that you don't have a proper plan yet.

    You are using a lot of language that is really vague. Narrative versus simulation, etc. What does that even mean? A few possible responses, versus a ton? That's just question of numbers, isn't it?

    If you wanted for X, Y, and Z actions that could possible happen to mean that A and B events can occur but not if event Y happened, unless it was on a Tuesday, but only if you romanced the blue alien after going on a taco date... I think it's completely pointless problem to solve because you could have exact same effect in much simpler ways. Like, players will absolutely never figure out any difference between a system that is an intricate web, versus one that just have weighted events contributing a final outcome, and maybe a few semi-random occurences here and there based on current weights.

    Filling that data out is just spreadsheet stuff - can be really simple and the final result is that choices do indeed matter, but you don't have a web to untangle or make sense of, instead you have spreadsheets and graphs to look at which is conducive to big data management.

    All the bold phrases you indicated exist in Mass Effect, don't though? I doubt there is anything unusually clever going on there, just an army of writers/designers to fill in the programmers system.

    Would be easier to understand if you could describe a single scenario in the game, and what sort of possibilities could derive from this one cause. Not how you expect it to work on technical level, just what actually happens in the game.
     
    Last edited: Feb 26, 2023
  17. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493

    It's really isn't that complex really,
    think of animation (cinema, tv), why all animations don't just reuse the same movement over and over? or the same shot? What I'm making is an extension of that in the dynamic space, I still have the generic stuff, and that's fine, but at some moment, to make it more unique, I need character to make some unique decision and thought process that only them have, to give texture and punch up.

    Imagine getting close to a dynamic animation movie, you can't have that with the sims. It's in between cinematics (unique animation, no code, no flexibility) and actual in game actions (generic animation loops, composable situation, interactive behavior). But I'm NOT talking about animation here, I'm talking about precisely unique thought process, as they create exception in the generic stuff.

    If you want a cat, you don't want it to bark like a dog, that example is over simplified, obviously, because you would think barking is just a sound data or an animation data, when I'm talking about the behavior itself. When you want a game cat to meow instead of barking as a behavior, you typically create a child class and override the parents with the new behavior, the difference is that I don't want to replace a whole function, but something dispersed on a tree. Probably there is a better way to organize the tree, but it wasn't "sub tree", because the problem don't lie on sub tree, and it wasn't traits, because I have those and they are polluted by exceptions too.

    Subsumption and observer like pattern are probably the right way to look at it. Subsumption because it allows to factorize code and MIGHT lead to separation of concern, observer pattern, because I can just run the tree without exception and intercept node signal that would match a specific character behavior that have a variants when it exist. And probably if I can get the cake and eat it, because it's irreducible, that also clue me in how to separate the structure (the tree) from the content (the node), so I can at least keep some legibility in the logic flow.

    The whole idea is to keep those specifics apart from the general stuff, so they can be added without messing with everything, that's it. It was never complicated. I was just trying to explain why I do it by explaining the context, and the wording is lifted from how we speak about it in some circle, I didn't realize it wasn't common knowledge around. I do have the generic stuff sorted out already, because I'm doing exactly what everyone is doing, I just have this extra stuff I want out.

    Let try to illustrate with a simplified example:

    original tree:
    node1
    --generic action1
    --generic action2
    --specific action character a1
    -- node 2
    ------specific action character b1
    ------generic action3
    ------specific action character a2
    ------generic action 4
    -- node 3
    ------specific action character b2
    ------generic action5
    ------generic action6

    Node 1 contains 5 actions, 2 of them are nested nodes
    Character a has exception in node 1 and node 2
    Character b as exception in node 2 and 3

    The goal is to get the exception out, such as the tree become generic for all character as:

    Shared tree:
    node1
    --generic action1
    --generic action2
    -- node 2
    ------generic action3
    ------generic action 4
    -- node 3
    ------generic action5
    ------generic action6

    with files for each character:

    Character a file:
    node1
    --specific action character a1
    -- node 2
    ------specific action character a2

    Character b file:
    node1
    -- node 2
    ------specific action character b1
    -- node 3
    ------specific action character b2

    That would recombine with the generic tree into the original tree. Treating extra behavior as data to input in a spreadsheet instead of having everything in a single dirty tree. That would allow to add character without problem.

    There is only two way: either I find a way to reorganize the tree such as specifics get together and easily detachable, or I find a way to tag back the specific at the correct place. I already use sub tree for anything that's below a high level node (say for example club activity).

    Also action here don't mean action in the world, they mean a bit of code running, they can pre process or post process of certain thing, they can modified behavior later in the tree, in way where these behavior don't have to be duplicated too much.

    Ultimately, I'm cloning a game that exist, there is zero uncertainty, and I just make sure the code is clean to future proofing, and that was the one thing that was rough after prototyping quickly the system to imitate.

    To be frank I don't understand why people are so confused, I only seems to get this confusion here on this forum.

    Only at a very surface and distant level. I linked at an article below that explain and tour around the challenge. But also I constantly survey the state of the art of what's done, so it's probably unfair to me to expect everyone who hasn't deeply thought about it to understand the actual nuances. Like if I point to Tokimeki memorial, how can you tell why the underlying system is important, do you even know tokimeki memorial? You have to be interested to get it.

    And the difference is all about the nuances, mass effect is a traditional CYOA structure with flags and stat gates, it's not dynamic in anyway, just branching, I don't know what game you have played or know enough about to point for a dynamic system, skyrim is in the middle for example, it has multiple rigid CYOA structure for it's story, but NPC has moment to moment reactivity and scheduling actions, in my case I don't have the CYOA structure, at all.
    https://emshort.blog/2016/04/12/bey...ased-and-salience-based-narrative-structures/

    https://en.wikipedia.org/wiki/GNS_theory
    My bad, I assume that was general knowledge, I have been using this termnology at least 20 years in the industry.

    For someone who say he doesn't care, that's some bitter soup you are serving me, on top of being nonsense because you can't read apparently, it's obvious you haven't read ANYTHING about what I put, I show which game does it, and how, and what's the difference. I mean there is no point in continuing discussion with you, you don't even engage with arguments and wax poetic about fantasm you have.
     
    Last edited: Feb 27, 2023
  18. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    They do that all the time, though? Videogames are doing that since 2000s. "Talking head animation" from bioware, from before "MoCap everywhere". Also see disney rotoscopy. Those were doing this at least since 1940s. Also see Wilhelm Scream. Also see generic movement reused in every ultra low budget unity-based weekend game in existence.


    Absolutely not.

    Your scenario describes OOP abuse, and while it works for teaching, it is a royally bad idea (as it is likely to lead to "model collapse"). Composition over inheritance. There's no reason to subclass when you can alter behavior through configurable data.

    I would create class "Animal" that would encompass all animals in the game and I would not ever subclass it, unless subclassing is impossible to avoid. Bark/Meow would be a different animation clip. The animation would have a slot for its "make noise" action which would plug in animation and sound. Which is what I described previously. This approach would also allow easy modding without source code access, because people would simply need to plug a different clip.

    Which is what I described earlier. Make subtree modules pluggable, like animation clips.

    So, regarding swappable part of subtrees, make those parameters visible at top level. Then change their configuration by plugging the tree you want through inspector.

    I provide advice I see as correct. If you're taking this personally, why bother asking for asisstance in the first place? There will be always people who will disagree with fundamental approach you took, and that is normal. However, if you got attached to the project, you're likely to get upset over disagreements and criticism. Which is why getting attached to your project is not a good idea.

    You're also producing walls of text. That indicates that you went in deep. It could mean that you may be another guy with overtones, or maybe you're on the right path, nobody knows, time will tell. However, for assistance with walls of text you'd need a full-time paid assistant and not a forum passerby.

    Also, why bother proving anything to anyone, including me? Just code. A wall oft text can take up to 40 minutes to write, a lot of things could be done in that time. As I said earlier, you went beyond beginner level, and from now on all problems will be like that. Welcome to the club.
     
    Last edited: Feb 27, 2023
  19. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    To be honest, it sounds like over complication.

    It is not clear what you mean by behaviors and thoughts.The bottom line is, we do something in the game, then there is a reaction. We know there is a reaction, because pixels change. That is the full extent of the truth as far as we are ever concerned.

    Whether you want the player to be focused on numbers or to see changes seemingly tied to character personalities and actions, at the end of the day, under the hood, the code is still doing essentially the same thing, isn't it? Character driven design doesn't mean that we simulate a human brain, instead of using simple, easy to manage spreadsheets or similar.

    I prefer not to lean on jargon for a couple reasons:
    • it makes people think they understand each other, even though it looks like at least half the time, they have very different understandings of the words
    • its often misused to feign expertise
    • it often obfuscates simple concepts that could be more intuitively understood using plain language
    • "if you can't explain it simply, you don't understand"

    Whether Sarah scoffs when we burp or she runs away screaming could be simply decided by a proclivity spreadsheet that she has for various actions, perhaps multiplied by her general proclivity towards you, which could be a dynamically changing value, but that all is just very simple math and each action you take in the game can add/subtract to that value.

    What situation would call for Sarah to make a more complicated decision? How would that more complicated decision change the experience that the player has?

    It might help to actually describe an actual scenario in the game. Like we interact with some character who host both general and unique actions. What is the full extent of possibilities (specifically) that can arise from that.
     
    Last edited: Feb 27, 2023
  20. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    In the end, it doesn't matter, the point is that I want to move some function out and have cleaner code, easier to edit, the whole thing about behavior and all is born out of necessity and I explained the rational, not all game have reactive type of ai, especially if you go beyond killing and informations NPC to social agency.

    EDIT: the reason I need it, is also that if I want to add a character, I just add it, not go in to the behavior code.


    But where do you draw the line? "gameplay" is jargon my mother wouldn't understand, I thought gamist, simulationist and narrativist where on the same level, it was common years back, at school, when I was a kid, and there was discussion about "doom vs final fantasy". And I was on the fringe of the culture center (caraïbe).

    I can only invite you to read the links I shared, since you are new to teh subject, tons of people has been working on this and there is tons of games used some implementation, mostly interactive fiction games (IF genre).


    EDIT2: also it's something that simply arise from experimentation with a prototype. If I wasn't needing it, I would not have add it. The thing is simply I need specific reactions, it's closer to verbal communication, that is a dialog without text, that typical actions, it's closer to this:
    https://emshort.blog/2013/02/26/versu-conversation-implementation/

    I could use a a rule base system, but then I would lose legibility, and that's what I'm concern with.


    Semantics and gaslighting, the point is that it's made of ONLY That, and i do have generic that reuse, the whole problem is about separating the too in code, not avoiding the generic.


    Nice try, cherry picking quote and not reading teh whole context (beyond what I quoted too).

    Also is this enough code to you? That's just one fragment, it's already in multiple file.
    upload_2023-2-27_11-25-49.png
    The dreadful trails of methods is why I keep the tree, mixin and traits make the situation worse.
    I'm in the middle of refactoring, so a lot of that will be rationalized, but I expect more functions, more file, as many need to be broken from the prototype state. The prototype is done, already, I'm cleaning. I ask about problem that surfaced.

    I wouldn't ask if I hadn't already commit, and I wouldn't rebuke you if I hadn't already try what you mention and can be discover with a basic google and a query to chat GPT. For some reason you think I'm stupid.
     
    Last edited: Feb 27, 2023
  21. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    I'd take a look into the ECS architecture. I'm having a hard time understanding how what you are describing here is unique, but it seems to me that ECS style has a lot of benefit because it gives a very consistent structure for data flow and decouples everything by default.

    With OOP, for every new thing it's always a big think on decoupling, responsibility, communication flow...each person has their own opinions on all of that, and even if you work alone your own opinions will constantly change. Because there isn't a best answer, you have to design uniqe answer for every question. THat's not sustainable for a complex project IMO.The way I see it, making a game needs to be like an assembly line. You figure out what our inputs and outputs ought to be, but you don't want to be designing the machines that convert input to output. If you do, all your focus will go into that, and there will be no time/energy left to focus on the inputs and outputs, which is the only part that actually matters to the audience.

    Honestly, OOP seems like junk to me now. Like, its fine for tiny games and is easy to think about conceptually, and has less boilerplate needed to get things rolling, but to make an entire game that isn't a trivial thing, I just think it causes a billion problems and makes game dev much more difficult than necessary. Just my experience of course.
     
  22. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    It's not incompatible, that's not the issue. It's not OOP vs ECS. I don't get why you are obsess about what is unique? The problem is that editing a flat structure obfuscate the logic, that's it. Why I want is to keep the tree structure in a legible way, because currently, it makes it that adding tons of complex behavior much faster.

    I tried going with "good" flatish structure, and I couldn't finish the prototype:

    - I couldn't track bugs efficiently,
    - I couldn't track the logic efficiently
    - I couldn't read and write new behavior efficiently

    I got back to the tree by necessity:

    - folding allow focus on what's relevant
    - unfolding allow to track a single line of logic
    - it allow to parse tons of behavior in a few line
    - adding new behavior is simply appending at the right place
    - complex behavior are easy to discern by following along the depth
    - huge list of behavior don't become a chore to navigate through, a lot less scrolling and jumping around the code, relevant things are nearby.

    Type of behavior that I do, and is possible:
    example from: https://emshort.blog/2013/02/26/versu-conversation-implementation/

    Typically people implement it as rule base matching with forward chaining, and I don't like it, you have a bunch of floating thing hard to see they relate to each other. It's hard to debug.

    Parameters only edition, only lead to "adverb" appending on basic actions, they don't constitute full activity. You can do better shooting, sloppy shooting, but nothing near the complexity of the example above.

    I could trade some slight code performance inefficiency if developing the game is effortless, it's a production issue.
     
    Last edited: Feb 27, 2023
  23. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    I just see a list of traits unique to each character, and certain facial expressions and sets of remarks could be mapped to characters and/or traits.

    I dunno, seems like that's the simplest way to handle this. I wouldn't want to juggle behavior trees or inheritance chains for this at all.

    collapsible code blocks I dont see as an architecture thing. That's just like, basic functionality of any IDE, isn't it? It can help with readabilitity but it doesn't help with ability to find things quickly in a huge database. Like, you absolutly do not want to have to visually find things with your eyeballs. Thats awful.

    I'd want for things to be categorized and named in such a way that I never have to hunt and peck, but can easily search the entire project via search. Ideally, search works even with unorderered inputs.

    For example, if I am searching for Expressions.Ryan.Angry.Angry003, I should be able to just type any of those words in any order, that way I don't have to remember much at all. So long as I can whittle down from large categroy, autocomplete should do most of the work for me. That helps make it such that my mind can stay on high level and not waste energy remembering details, or build frustration by wasting time trying to find stuff.

    I don't see how a tree would be preferable to named, encapsulated actions that I can easily narrow down via a categorized search. The name of the action would pretty much tell you what it will do, and it can handle possible transitions by passing name of desired actions in an event.

    That way, you don't have to visually look at a tree and try to understand it. Where code is an the way it is layed out doesn't really even matter. Only thing you have to do is ask, "okay so if a character is angry and we burp in there face, what might happen?" so you start typing, "characters... reactions... angry.... " etc and pretty quickly you have all the relevant actions realted to this. You open up your action and in there you can easily see only the stuff that is going to happen for this unique situation.

    anyway, if you think this isn't helpful, sorry for wasting your time. If you want experts advice on the matter, you probably ought to reach out to the people who wrote that article directly I imagine.
    Though I think there is a world of difference between solo-developers focused on getting a product out the door to pay rent compared to employees or salaried researchers that have a vastly smaller scope of responsibility and breadth of decisions to make. So the way pro's are doing things I don't think is necessarily good way for solo developers to follow.
     
    Last edited: Feb 27, 2023
  24. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    If you can do it fine, I'll see the result :p notice this isn't just reactions, they are whole chains of interdependence

    That wouldn't be how it work though, you assume the relevant part is at the leaf, but I keep saying it's NOT a behavior tree, it's not a decision tree either, those use leaf based selection. It's more each layer have actions and it read like a sentence: that is it's Ryan getting angry, it's more like:

    - hear himself evaluated negatively (perception) -> get angry (set emotional state) -> rude gesture (broadcast expression) -> storms out the room (pathfinding)

    - hear himself evaluated negatively -> get angry -> rude gesture -> start a fight with( his father )

    That would be horrible if you were to select basic stuff, thankfully that's not how it is organized. :p

    If I want to increase the basic range of character, I can just add a subtree at emotion, then a subtree of expression to that (that other character can perceive), then I set proper action goal, which is handled outside the tree, and which select audiovisual data. So when I unfold the tree, it's the logic grammar that unfold. Specific character can have specific "grammar". It's not a database search.

    That's not the problem. Also I do have parameters and traits, TOO, it's not that I discarded them.
     
  25. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    Well you've written these as unique things, but they can all be generalized, cant they? And then they only need a specific target for context.

    - hear himself evaluated negatively -> get angry -> rude gesture -> start a fight with( his father )

    could be

    GossipReaction (gossipTarget, gossipInstigator, gossipValue, uniqueHandle)
    {
    given gossiptarget and instigator and gossip value, update my current status
    if uniqueHandle is valid, dispatch it so that it can be handled with a unique action
    }

    get angry = anger state is just the value of current status. Probably you map various emotions to each other character.

    rude gesture = a set of possible reactions, per character, per emotion type

    start fight with father = a unique action, triggered by the handle


    I'm not understanding what the problem is though to be honest.

    I just see traits as a database of something like enums mapped with a number value to describe how a character currently feels about other characters and possibly more abstract things like other relationships between characters.

    for example, Ryan has components to describe his sexual affection for Sarah, which is current 1, max value.

    Ryan also has component to describe his passion about relationship of Sarah with X, where X is any other male. You could describe the X in a proclivities spreadsheet per character.

    This way, you could describe if Ryan is violently jealous or meek and passive in general, or just about certain other guys. And it's just two nuggets of data and a number that gets updated bases on actions that he can witness.

    So if Ryan is in the level at the time some action which contributes a value towards Sarahs sexual relationship, then Ryan is updated as well.

    Actions update those states, and in the circumstance that you have an action that would only ever fire for a specific character given unique parameters, you just call it with a name directly.

    What is the benefit of trees here?
     
    Last edited: Feb 27, 2023
  26. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    No matter what though, you have to physically author the animations and write possible dialogue choices, so I dunno why some procedural system would be beat something authored but with some semi-randomization mixed in. I mean, player could playthrough a 100 hour game 10 times and not see duplicate content if you just have a pool of possibilities for dialogue / expression to be chosen from.

    It seems like the value of a game like this would be in the understanding of human character and expression, not in a technological advanced procedural dialog system. Like, the tech isn't going to generate worthy content - it's only answering the question of what outputs to spit out. The only thing that truly matters here is the inputs and outputs.

    So I kinda challenge the entire premise here. Not clear what you aim to do, why, and you are talking only about the how but it's not super clear what the exact problem is. Maybe somebody else knows, but it's a lot to read and only once have you given a concrete example that's readily understandable.

    It does seem like you could leverage something like chatgpt for a situation like this, but I don't think you're going to get help with the most cutting edge tech on the forums here. I think you need to already be an expert on that front, to be thinking about making viable products with it.
     
  27. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    I have no idea what gaslighting is supposed to mean here. Your example is wrong, I pointed that out.

    If you want to make part of a subtree customizable, make it a pluggable inspector field at the top level of the tree, and plug relevant function for each character. If there are subtrees, make the same for subtrees. That will produce a modular approach to AI trees which will be easy to customize.

    Either way it is obvious that you've decided to be upset and now are going to waste time "defending honor of your clan/project" or something like that while sincerely believing that I'm acting out of malice. So no further dialogue will be possible.

    You've been given information, past that point this is not my concern. "It is your pet project" means that it is not my concern what happens to it. Also, like I said, there's no point in proving anything to anyone. You believe you're right - keep working on it. Time will tell if you were right or not.
     
  28. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493

    HOLD ON what do you think I'm making here? I think you are going too far! :eek:

    I'm not making cutting edge anything, i'm cloning indie games making by small teams of barely 1 person:



    I keep saying I'm cloning this game without the shady elements and with zombie instead of students. I don't get why you say I'm pushing state of art of anything. I'm literally just following PUBLISHED techniques. There is literally no uncertainty.

    The code isn't meant to revolutionized anything,
    its meant FOR ME TO EDIT FASTER without compromise. I keep saying flat method didn't worked out, and people keep telling me to do something that hasn't work for me. I dunno.:( My method is plenty general, I don't even need to introduce a gossip method to make new behavior. I just wanted a way to separate generic and specific and people lost their god damn mind.:eek:


    What the F are you talking about, I told you you aren't helpful and keep coming back with the most bizarre statement. That's why I'm upset, you are like not even reading whatever I said.:confused:
     
  29. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    Well, I read and reread your post a few times to try and understand, and probably only 20% was able to be understood. And I did google strange words, but in at least a few cases it still didn't make sense.

    You mentioned issues with the behavior tree, and how you struggled to not have unique actions inherit from the entire tree. I pointed to at least one architecture that has helped me do away entirely with behavior trees and inheritance, at least in a simpler AI. I don't see how it would fail to scale, or how your method, from what I understand, would afford any benefits.

    So try it or not. If it's useful, great. If you want to stick with what you have, that's fine to. Personally I wouldn't count on just collapsing code and then having to physically read through it to decipher complex if/else chains. That sounds like a nightmare that would lead to burn-out really fast to me.
     
  30. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,980
    @neoshaman I understand that you are passionate about your points but reading this thread you are coming across as a little aggresive, which is not like you usually on these forums.

    Clearly this is important for you to get right and we all support you in that, so lets take the anger/aggression down a notch? I think it will greatly improve the help/discourse you attract in this thread, and reduce chances of it getting locked :)

    This is all text based so its easy for us all to misconcieve what or how something is being said. I dont think anybody (including you) is meaning to be aggressive or annoy anyone, so lets all be civil :)
     
    neginfinity likes this.
  31. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,770
    To be honest, this thread goes with too many fancy words and like trying defending one particular type of design approach, while not even considering anything else.

    There are clear signs of over-engineering, based on how problem is presented in the thread.

    Easily can fall into such over-engineering rabbit hole, when working solo, while having gaps in subjects and locking self into one committed route, because of being so invested.

    Stepping away for a bit, and even trying prototype different solutions, can help seeing pros and cons of the designs.



    Personally as already mentioned in this thread, I would look into Sims, since they got both great modding support and high variation of character behaviours, with generalised mechanics. That includes state of relation and behaviour toward other characters.

    Sims 2 and 3 are really good example, if study modding files. There is no specific files type, per character, to change individual behaviour.
    Modding support dynamically creating during gameplay classes, relations between classes etc.

    For example group of vempires may don't like elves, but are ok to go with ghosts, in terms of relations.

    Certain level of modding is just data driven design. And so that should be the focus of the design. Unless creating some specific animation sequence, or new utility, like wash machine, which may need a bit of scripting. But nothing too complex or fancy.


    Civilisation 3 if I recall was mostly data driven. While variations of unit and their behaviours were made using excel files.


    Another project I would look at, is factorio. How they achieve so much variations of machinery and relation between one to other.


    For another characters AI, a bit like sims, is rimworld study which I would suggested. It, is highly complex behaviour of relations between characters, groups of sosaietes, or even groups of few character social classes. I.e. slaves, wardens, or other classes.
    Modding is supported as well.


    Skyrim would be another suggested game to get study, since it has well established modding support.


    I so wonder, how come Utility AI is completely ommited in this whole discussion, while allows to achieve highly complex behaviours, with relatively little effort and complexity, while supporting data driven design. ECS like system / components design architecture would allow easily add new behaviours.
     
    Last edited: Feb 28, 2023
    neginfinity likes this.
  32. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    Keep it civil and non-argumentative, and thread can stay open.
     
  33. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    I appreciate all concern, but I think context is lost. So I moved away. Also I had a bunch of bad stuff happening like my hard drive dying and I was on linux on stick, while having to wait for buying a new DD, but there isn't store here selling internal hard drive. So while I had my work saved, I could not return to windows.

    Outside of that context

    I tried the stuff being advise before these were told, and they don't work, I explained why, but people keep ignoring the why and the fact I tried them ALREADY, that's frustrating.

    I mean I get the context is a bit hard to understand, probably me being deep in the exercises as it's not my first take at it.

    1. There was a lot of YAGNI advice, a lot that focus on doing another type game or doing premature optimization. And I don't need a mass of them, if your story is need for 30 000 npc to partake in the story, you are doing something wrong, at best you have on average 10 importants character with complex behavior, if you need background crowd, that's another AI entirely.

    2. Absolute disregard for the need for legibility, everytime I say the tree allow to keep the logic context, unlike implementation that obfuscate it in favor of advantage I don't need, like performance (ECS) or flat structure (array or long trails of method). Also flat list like advised are O(n²) a tree is O(nlogn), so I can reduce a list of 18 quintillions to just 64 checks, I don't have that much line, and scheduler can handle up to 1024 if without ever slowing down.

    3. Disregard for the fact that I already have something that worked, right now, not hypothetical, so advice about how it wouldn't allow me to do X are by default wrong. I'm refactoring i'm not designing. It's DONE.

    4. Disregard for the type of game I'm making with advice to make another game (like the sims, I'm not making the sims, i'm not making crusader king, and i'm not making critters simulation, not a crowd simulation).

    5. Disregard for the Core problem. That is, I have issues NOT with the design, performance, or ability of the system to perform. I merely have a problem of organization, and it's for future proofing.

    6. Advice that tell me to do something I have in the OP and in many post. How many time I have to mentioned I have UTILITY AI, why do people here keep telling me to add utility when I said multiple time I have it? Utility by itself is too simple, so I have another layer to support it. I mean did you implement it yourself? How did you deal with oscillation and various threshold effects? Was it easy to figure out the bugs? I did and I solved it those by adding a new layer.

    These advice ARE over engineering. And they don't adresse the core problem, which is separation of concern. You can not go simpler than a bunch of if, I'm definitely NOT the one over engineering. If you want to use a hammer solution, be sure the problem are nail problems.


    ONLY Tony Li offered an advice that make sense, it wasn't a direct advice, but it was from a place where he understood the problem in context, no wonder he works on assets that does similar thing.

    The thing is the wall of text were trying to over explained the context, I think people are just not familiar with this specific issues. Which mean there is probably a culture clash. I assumed these were known because these type of discussion are OLD in dev and player circle, we were constantly having them back on Tigsource forums, but I realize that maybe people 10 or 20 years younger missed those, and the death of forums mean those knowledge were not passed on. The whole simulationist and narrativist were concept taken as given.


    A. YAGNI, premature performance.
    My code go around 1ms for 100 characters, i won't ever need more. I can probably separate background character from important character, but YAGNI, the scope is small, no need to increase complexity for performance I don't need. So yeah keeping flat array of number is more efficient, and now I can simulate 30 000 simple agents at 0.25ms, except that's not even a bottle neck. And it doesn't help design complex behavior.

    B. It's not a random simulation of agent
    I think that's the one that's hard to grasp. It's closer to a fancy dialog tree than your typical game ai. That is behavior are simplified with an external look up table (schedule table). You have a reactive ai that detect elements to branch in and out from the schedule (narrative events or reactive behavior). There is no complexity. Think game NPC like harvest moon.

    C. It's a story driven ai.
    The problem is not the ai per see, it's writing scene, It's like a dialogue tree, where the options are the game interactions, you don't select the text options, you do stuff that flag an option on the tree, and the tree isn't made of text, it's made of character acting specific actions in a scene.

    D. It's a story driven game
    The story are told by scenes, the scene are just specific behavior, the scene are a tree that branch on the game state triggered by the player and consequences of actions done by the player. NPC are dumb brick that follow a scripted tree.There is little real interaction between NPC. Mostly like games like stardew valley. NPC do not think, they implement the story.

    E. Scene drive specific behavior
    Because the scope is small, designing and editing the scene tree (events) are key. They are executed seamlessly within the world, with NPC going to spot where they perform the script. The script has many options to handle interruptions and branching. It's like game like harvest moon, if you marry a NPC, its schedule change to a new schedule, and some NPC have new state, that's it.

    F. Scene scripts are the contents
    Most scripts don't repeat at all, the scene is consumed and told the story, some are reusable and change its course based on state of participants. That is the AI is simple. In some way, scene scripts are the game level, how you perform at one level, will effects how the next level are played.

    G. It's not the sims
    I tried Sims ai, it generate blob character that are expensive to maintain. The character tried to do everything and the behavior are generic by default, having a love state at 0.6 or 0.9 doesn't have enough nuances for a real dramatic scene, instead you get infinite permutation of rules to handle everything. Instead of doing generic animation, I do the whole behavior PER scene and reuse part that I can, by using a check on the tree, there is a limited number of scene, so there is no possibility explosion, scenes are self contained.

    H. I need to debug STORY bugs, not code bugs
    The reason it's a nested tree of behavior, is because it maintain context in the face of divergent behavior. When I code the funerals of the father scene, 0.6 vs 0.8 tell me nothing about why a character does something weird, and shifting 0.6 to 0.4 doesn't tell much about how good a scene is.

    I. All scenes are different and uniques
    And the mother funeral scene will be different anyway, because character would have different relationship, number won't give you the nuance, so you script the code directly, because there isn't an infinite funeral scene, just those on the story path and i'm not trying to do a an AI that pass turing test.

    J. The core of the ai is a single external entity.
    Basically the NPC obey a schedule table, the schedule is own by an external structure, the NPC must know how to implement individually specific actions (personality). The AI also sets the NPC state based on global game variable (or the NPC query on the table which state to be in), like flags and various variable. It's like combat where the whole level is in alert, even though NOT every single NPC has seen the player. EXCEPT that instead of alert, it's various story or world state (for example a gloominess level when there is a lot of murder, the NPC look at the table and set their behavior to afraid, then each NPC implement "afraid" based on their personality).

    K. The external AI is basically the story state table.
    It's the thing that control which events fire, it's not complex, it's just another global fancy dialog tree, but instead of dialog, you have a bunch of table that sets NPC behavior. If you want to code another story, you basically change the table, and you probably add necessary content (new event scripts when rearranging existing one isn't enough).

    That's a lot of point to tell you it's not crusader king and it's not the sims, it's its own game doing different thing. It's more like game with scheduled NPC like harvest moon. It's done and working. The issues is a refactoring issue.


    I just wanted to see if people knew about way to separate responsibility, not redesigning the game into something else that's it's not. Basically point J is where I have issues, i would LIKE to keep responsibility of character WITHIN character in, their own file.

    1. Consider the observer pattern:
    The observer pattern allow to decouple behaviors. It doesn't solve my problem per see, because it work mostly for well defined but singular actions, my problem is that the behavior are too entangle. But that's worth keeping in mind.

    2. Consider separating the tree and the logic.
    The tree has meaning that help legibility. It help to keep context, because higher level implement stuff for lower level, having STORY BUG tracking is much easier when I can see in which context a behavior is expressed. Like I said it's a fancy dialog tree, it's like choosing a topic and then inspecting which line doesn't make sense in that "topic". Separating the tree and the logic would be hard because I would have to create a tools and juggle between the tree (topic equivalent) and content (sentence equivalent).

    3. Consider JSON and XML for the tree
    If building a tools is a problem and we have to keep it simple, why not use thing that are already exist (duh), any basic ide have folding for these format. So I don't have to do anything too complex. I still have to figure out how to write logic with these, which is where LUA s probably a good options too, if I can figure out how hard it is to implement.
    3b. DIFF TREE tools exist for XML
    I don't know for json, but a diff tree compare a tree to another and tell you the change, there is tools for xml, so I could edit the tree per character and automatically save the difference in a file. I don't know how to do it concretely, but that's a lead.

    Conclusion:
    Each of them adresse concern with the above, the observer pattern make a whole lot of sense if I have the tree separate from the logic, such that the logic could listen to the tree and implement the corresponding node by selecting a generic or specific varient per character, extra subtree being kept on character.

    4. From Tony Li: Break the decision tree further
    I DO HAVE UTILITY AI feeding the tree by preprocessing checks. But yeah the idea of breaking it more is such a simple idea, like duh, why I'm not doing that? is there opportunity for it? I said I have context nested for legibility, all I have is to recognize these contexts and generalize them.

    The idea of subsumption layer is clever. I realized I had it, but didn't really knew how, well the concurrent top level SCHEDULE, EVENTS and REACTION node, can been seen as subsumption layers, each implementing from global and long term to specific and short term behavior. Now I need to look if each subtree of these can also be organized on layer, so maybe after that I will have new opportunity to further separate data if it made clear some hidden redundancy.

    Someway responding to BIGTIMEMASTER hint at how I can do this, when I spontaneously break the rules in layer from perceptions to actions, the sub layer emotions and expressions are the things I would need to identify and generalize.

    I'm not sure if anyone have something constructive to add, I don't know if that conversation has need to continue. I'm not sure if anyone will get something out of this, I don't think people are interested in the type of game I'm making, I'm not making the sims nor crusader king, I don't want to.
     
    Last edited: Mar 12, 2023
  34. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,770
    Why don't we ping @TonyLi in this thread, if so mentioned person may times.

    Would be also easier, if OP record short vid, of mentioned working system.
    Possibly would would be easier to understand, than walls of text.
     
  35. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,694
    I don't have much to add beyond my original post in the thread. A simple implementation would be a stack of lightweight FSMs, where higher FSMs could interrupt lower FSMs, and the lowest FSM would be the default schedule table to follow if nothing more important is going on.
     
    MadeFromPolygons and neoshaman like this.
  36. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    For sake of completion:

    People asked for the code, I was pretty sure it wouldn't change anything, and it wouldn't be useful, and I was in the middle of refactoring, anyway I made that for people interested, created from another discussion.

    That's the original (but cleaned up) shape, before I asked any questions anywhere, I haven't figured out yet what to modify anyway.

    PSEUDO CODE!
    Code (CSharp):
    1.  
    2. //Black board:
    3.  
    4. //(reference to global ai sets on initialization, hold world state)
    5. AiManager Manager;
    6.  
    7. //hold all var and flags relative to interaction in the immediate sensing radius
    8. Struct PerceptionBoard;
    9.  
    10. //character data such as persona, stats and other that can be modified, managed by  the 3 decisions layer and consumed by the action state machine.
    11. Struct CharacterState;
    12.  
    13. void Update(){
    14.     if (isActive & isLiving)
    15.  
    16.         updatePerception();
    17.  
    18.         //Kind of a Subsumption architecture
    19.         //select the proper behavior with 3 "layers" of if tree
    20.         //Idea proposed was to get the most complex one and find way to break it further in layers. By finding pattern to generalize.
    21.         updateSchedule();
    22.         updateEvents();
    23.         updateReaction();
    24.  
    25.         //Actually do the behavior
    26.         performActions()
    27.  
    28.     else if (!isLiving)
    29.         updateDeath();
    30. }
    31.  
    32.  
    33. void updatePerception(){
    34.  
    35.         //Fallthrough pattern (concurrency: just DO don't exit, all node execute in order, order don't matter)
    36.         GetPlayerDistance();
    37.         UpdateDetection();
    38.         //...
    39. }
    40.  
    41. void updateReaction(){
    42.  
    43.         //priority pattern (exit on success)
    44.         if( gotPushed() ) return;
    45.         if( gotHit() ) return;
    46.         if( gotAlarmed() ) return;
    47.         //...
    48. }
    49.  
    50. void updateSchedule(){//also updateEvent
    51.  
    52.     //Complex tree of functions with various ALTERNATING ai pattern as "actions", really should be renamed to "decision units", will clear some confusion
    53.  
    54.     //behavior tree pattern (generally wrapped into function to resume to the proper node after exit,
    55.     //if it helps legibility or same type of decision is repeated accross node)
    56.  
    57.     //sequence pattern (exit on fail)
    58.     if(!function1()) return;
    59.     if(!function2()) return;
    60.     if(!function3()) return;
    61.     //priority pattern (see updateReaction above)
    62.     //fallthrough pattern ("concurrency": see updatePerception)
    63.  
    64.     //Preprocess units (Order matter, do stuff for nodes and units further down, generally before a nested node tree)
    65.     function4();
    66.  
    67.     //Nested node, precise a specific steps into a sub selections,
    68.     //node CAN follow behavior tree pattern too with return on fail or success
    69.     //or breaking the whole tree traversal.
    70.     if(PerceptionBoard.check1){//prefix node indicating the task
    71.         //interleaving pattern implementing logic, in any necessary order
    72.         //->decisions units as sequence units
    73.         //->decisions units as priority units
    74.         //->decisions units as fallthrough units
    75.         //->decisions units as preprocess units
    76.         //->decisions units as nested node units
    77.     }//suffix comments telling how much line there is, should add number of units and nodes instead, now thinkig about it...
    78.  
    79.     //more interleaved units and nested node
    80.  
    81.     //Observation there is a lot of "preprocess units" in the actual code.
    82.  
    83.     //problematic and specific node/units (happen at all hierarchy level of the tree)
    84.     if (functionOrCheck() && isNAMEcharacter) ...
    85.     if (functionOrCheck() && !isNAMEcharacter) ...
    86.     if (functionOrCheck() && isPersona) ...
    87.     if (functionOrCheck() && !isPersona) ...
    88. }
    It's legible because you read it top to down with folded "node", and ONLY open nested if you NEED more precision, node have short prefix comments to replace the name and short suffix comment to indicate the line numbers. Node have a cascaded logic that is readable as if they were on a grammar like.

    A cascaded line tend to be short to read, because even though the code is 10 000 line long just for the tree (with the other half being tucked into functions as sub tree), you only read 100 lines at a time. A tree is naturally exclusive, so if you go down a path, you generally don't need to look at the other path, and therefore YAGNI, you don't need to jump around trying to understand stuff, each layer does a specific stuff

    And since the logic is cascaded, it flows very naturally from general context to specific context. The issues being is that every character has its own way to "sit" or do any actions, which increase the width of node and inflate line counts artificially, with cascaded logic it spread the behavior along the tree depth. Splitting the tree in subtree or rules don't solve the issues because now you have unstructured jumps.

    From: goto considered harmful.

    Having this experience first hand, I left the tree full.

    I thought experienced people knew about solution to split a tree "longitudinally", but like the cat sez, I might have reach a point where I'm no longer a beginner.

    EDIT: writing this made me realized I can have my cake and eat it too, I always wanted "breakable if", and now I figure out I can encapsulate node into lambdas!
    Code (CSharp):
    1. //Breakable node
    2. () => {if (check){
    3.        //code
    4.        if(condition) return; //break from the node
    5.        //code
    6. }}
    The joy of not having to implement a whole verbose node class to maintained!
     
    Last edited: Mar 17, 2023
    kdgalla likes this.
  37. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    This is perfectly compatible with the idea i described earlier.

    The code fragment represents top level decision tree.
    Now, if we take, for example, updatePerception(), this can call a delegate, a unity event, or a subcomponent, perhaps even placed on a child. For example, there could be IPerceptionComponent, from which you'd derive a perception behavior, and place it onto the same object or onto its children. The main tree would grab it via GetComponentInChildren (it works with interfaces), or use event whatever. The point is, that makes perception customizeable, and you can replace it with a different module.

    Submodules can be further organized the same way.

    That allows you to create different character AI templates, based on external configuration, based on inspector field values, or based on prefab. Which is what you asked in the very first post. You can even mix that procedurally.

    What's more there exist a concept of a callback, where the tree can modify its child nodes at runtime by replacing them with a different lambda based on external condition, which will make it harder to debug.

    And by doing that you'll get modular structure.

    There's a very useful concept with an idiotic name called "Dependency Injection" which basically means using callbacks instead of passing hardcoded functions or data. Using any sort of callbacks allows you to write your top level logic once and keep it unchanged, while the functions it calls customized through data, by setting them in inspector, on gameobjects or scriptable objects. Now, the issue here is that you cannot jump between nodes of the deep branches of decision trees, but you can interrupt the whole tree via exception or special error code, which would make all subtrees stop, control would return to the t op level tree and make it reevaluate which node should be active. A reboot of the AI so to speak.
     
  38. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    Yagni, perception is rather uniform on the scope of the project it doesn't need modularization. Plus I specify the issue is on the "selection tree" (schedule, events and reaction), not on those aspects. I already have inspector and values modifications, that's not the problem specified.

    Yagni, that's not a problem I have, the tree is static and won't change.

    I don't see how that help the issues specified, I do know about dependency injection, it's implicit when I talk about node substitution, but that's not the issues. NOTE: I don't JUMP accross branch ever. It's closer to a linear command line, the tree is traversed in set depth first order, with each node being just a

    You failed to address the issue explicitly stated:
    - legibility and context tracking for behavior editing, you propose idea that break the tree further obscuring context.
    - separation of concern, I want to separate shared behavior from specific character behavior, which lead to
    - problem of "specific behavior" dispersion along the tree hierarchy, that's the thing that prevent easy modularization with sub tree and other injections methodology, due to the nature of specificity needed for the project.

    For example adding hooks (dependency injections) on the tree for specific behavior at certain key node don't work, because "specifics" dispersion is unique among each character (because they are unique), I will end up with per character "unique hooks", which lead to the same problem of polluted tree. Either I find a way to generalized behavior into not being dispersed, or I find a pattern for dealing with the dispersion into separating them (like diffing tree).

    Basically:
    selectionTree(){
    Command1
    Command2_specificToCharacter1
    Command3_preprocess
    Command4_specificToCharacter2
    Command5
    }

    You can't interchange command2 and 4, because command 2 rely on preprocess of command3, most character don't overlap in command except in generics. When I enter a node command, that's the same things. I mean it works, I don't really need to disentangle it on the scope of the project, but I can do it I would, because next project gonna expand, and I need to build on what I learned.

    You keep proposing the same ideas, I keep telling you they don't apply because you ignore other points and context. You focus on teh top level logic (update function) but ignored the actual main function where all the explaining comment are in (the updateSchedule).
     
  39. vintage-retro-indie_78

    vintage-retro-indie_78

    Joined:
    Mar 4, 2023
    Posts:
    285
    not sure this is the best, atm working on a simple AI that's based on raycasting a grid in front of the character, idea is to use for object detection // basic navigation, however also have an idea for a bigger 8 x 8 m grid scanner that detects the height of a secondary collision layer beneath the normal ' map ', or area . . .

    the idea is to store locations for objects in a ' info ' collision layer beneath the normal one, and for instance, IF height of this place is 1.7 - 1.8, then == health kit, and the creature, or AI finds the stuff more live, instead of having a massive list, and then there's a grid scanner, or raycast that scans an 8 x 8 m grid ( 64 locations, at 60 FPS it scans that area every second ), anyway the point working on making an AI that's more dynamic, than static, and where the creature moves around the level more randomly, and ' reacts ', instead of learned routines, or say cover, health locations . . .

    Animation (21).gif

    this is an overview of a small grid in front of the creature, where it scans for height, more for nav, or walking more effectively, however been thinking of storing more information, by having the normal terrain collision, and then a second collision layer, made of 1 x 1 m bricks beneath the normal world, where a raycast is checking for other stuff, so the creature is ' intelligent ', or is aware of the surroundings, and then stores important information, or say the nearest cover positions in a small array, and sort - of constantly learns from the surroundings, instead of being more pre - programmed, or coding the stuff for each item, cover stuff, etc etc . . . .

    not really an expert on AI, however think making it more dynamic, and using raycasts to figure various stuff, might make more interesting, or ' dynamic ' AI, not sure makes sense, atm working on a prototype, more for walking around stuff, idea is to make a script one can attach to any creature, set between a few different grid scanner - types, and a few parameters for movement speed, if looks for cover, health, other stuff, and once that's been made perhaps have a basic // ' dynamic ' AI system that works at least to give interesting, or more ' improvised ' behavior, or a reacting-to-areas system, not sure this is effective, or a bad idea, each frame the raycast scans one grid - area, so it's just one raycast scan every frame, so the code is both light - weight, and could give mostly intelligent, perhaps also responsive AI, once the code is made, also then optimized should give a variety of creature intelligence, also for using items, getting health when injured, or finding nearest cover, right now that's my goal, however it's for a project where there are only 5 - 10 enemies on the screen at any time, not sure how effective it is, goal right now is also to make more effective nav . . . .
     
  40. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,147
    ChatGPT (both GPT-3.5 and GPT-4) keeps suggesting a decorator pattern.

    https://en.wikipedia.org/wiki/Decorator_pattern

    Based on your description, it sounds like the Decorator pattern might be a suitable solution for your problem. The Decorator pattern allows you to attach additional responsibilities or variations to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

    Here's how you could apply the Decorator pattern to your problem:

    1. Define a base Behavior class that represents the generic behavior tree. This class should have methods for evaluating the tree and executing the actions.

    2. Create a CharacterBehavior class that extends the base Behavior class. This class will represent the behavior of a specific character and will override certain parts of the base behavior. You can store the character-specific variations in separate files or classes, depending on your preference.

    3. Define a BehaviorDecorator class that also extends the base Behavior class. This class should have a reference to a Behavior object (which could be either the base Behavior or another decorator). The BehaviorDecorator class should delegate the calls to the wrapped Behavior object by default and only override the parts where you want to add or modify the behavior.

    4. Create specific decorator classes for each variation you want to apply to the behavior tree. These classes should extend the BehaviorDecorator class and override the methods where you want to change the behavior. You can use these decorator classes to insert, inhibit, or replace nodes in the behavior tree.

    5. When constructing the behavior tree for a specific character, start with the generic Behavior object, and then wrap it with the decorators that correspond to the variations for that character. This way, you can dynamically build a behavior tree that includes the character-specific variations without duplicating the entire tree.
    Here's a simple example in pseudocode to illustrate the concept:

    Code (csharp):
    1. class Behavior {
    2.   evaluate()
    3.   execute()
    4. }
    5.  
    6. class CharacterBehavior extends Behavior {
    7.   // Character-specific overrides
    8. }
    9.  
    10. class BehaviorDecorator extends Behavior {
    11.   Behavior wrappedBehavior
    12.  
    13.   evaluate() {
    14.     wrappedBehavior.evaluate()
    15.   }
    16.  
    17.   execute() {
    18.     wrappedBehavior.execute()
    19.   }
    20. }
    21.  
    22. class InsertionDecorator extends BehaviorDecorator {
    23.   // Override methods to insert new behavior
    24. }
    25.  
    26. class InhibitionDecorator extends BehaviorDecorator {
    27.   // Override methods to inhibit certain behavior
    28. }
    29.  
    30. // Constructing the behavior tree for a specific character
    31. behavior = new CharacterBehavior()
    32. behavior = new InsertionDecorator(behavior)
    33. behavior = new InhibitionDecorator(behavior)
    This approach should allow you to maintain a generic behavior tree, selectively override parts of it for specific characters, and keep your code organized and maintainable.
     
  41. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    No. Yagni means you shouldn't implement modularization until you need it. When you have a lot of code with swappable fragments, you need modularization, and the swappable fragments should become modules. The need has arisen, time to modularize.

    You'll need to define legibility and context tracking and criteria for their evaluation first, then you'd need to decide why those metrics and qualities are even necessary and whether they're necessary at all.

    I propose how I would approach the problem. I'm not bound by trying to stick to whatever approach, and would try several until I find the one that works. Anything that does not work, I'd throw away. Like I said, the idea is not to get attached, because that clouds judgement. If I end up in a situation where I'm absolutely in love with the approach I've chosen that's a red flag indicating that I'm probably wrong and everything should be double checked. Emotions cloud judgement. Things that amaze you and clever implementations can be programmer's traps that will drain development time without getting you closer to your goal. Things that work matters. Things that are beautiful but do not help are probably bad decisions. The key idea is that human mind is irrational, but programming is a logical discipline, so it is a good idea to watch out for your own irrational behavior. A solution that is ugly but works, is good. A solution that is beautiful but does not bring significant advantages can be a bad idea. And so on.

    In this scenario I'd implement "behavior override" asset which define character behavior, where character behavior is a collection of individual module overrides for each tree, and that collection constructs character tree or acts as it. Yes, a behavior might end up broken into a dozen modules, but that's no issue. There's no reason to implement a characxter as a single object, a collection would do. Character is collection of modules, modules are reusable across different characters. Decorator pattern suggested by @Ryiah is also a good approach, effectively that one implements a "feat" or "character trait" from sims. In this case feat does not know about character, it is an action that is invoked when relevant situation occurs. So, from character centric, situation changes to event-centric.

    ----
    One important thing.

    Please bear in mind that I'm largely a neutral party, so getting, for example, angry at me won't achieve anything useful for you or your project. Likewise, there's no point in trying to prove me that your solution is right. Because that's not my concern. Nothing changes for me regardless of whether your project succeeds or fails.

    Due to still being a carbon lifeform, I absolutely can get irritated when people act stubborn, irrational, or hostile, or ignore advice, or the amount of time spent does not result in anything useful. That's a consequence of being a biological organism, I can't get rid of those traits completely.

    However, from your point of you it'll be much more efficient for you to assume that I'm similar to another ChatGPT. Meaning I know things.
    Some of them are useful to you. Some are not. Some of them you already know. Some knowledge you may have is missing in me. And some knowledge I have you do not possess and never will. The difference is that unlike ChatGPT I have agency, meaning I can get bored and walk away from uninteresting question or the one where I spent a lot of time or gained nothing. Or spend inordinate amount of time on a problem that spark my interest.

    So rather than trying to fight and acting upset, it'll be a far better idea to fish useful information out of me.

    Something to keep in mind.
     
    Last edited: Mar 18, 2023
    Antypodish likes this.
  42. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    See python and lisp function decorators for inspiration.
    In this example, one possible approach is to implement a decorator which, when installed, wraps around "selection tree" method, takes the original method as an argument. The argument can be passed as an argument, or through lambda function. Meaning

    Code (csharp):
    1.  
    2. System.Action originalFunction = ...;
    3. System.Action selectionTreeWrapper = () => {
    4.   preprocess();
    5.   originalFunction();
    6.   postProcess();
    7. }
    8.  
    Those can be chained, made into a stack and whatever you want. You can also store a list of decorators to apply to a specific object within ScriptableObject. In this case you can also inclose shared state (shared between preprocess and postprocess) within a single class, and that class can be made smaller module than a character.
     
  43. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    I def ask chat gpt too, I def try that, before even asking here, unless there is something I missed, I end up with swapping a 10 000 line tree with another copy of 10 000 lines with variation at key node. Problem is that node are trees too, i can't just wrap a node without taking the sub tree too. So it lead to a lot of unnecessary duplication. And I still have to deal with the fact it essentially mean create a bunch of broken behavior which end up as a flat list of method, or a flat list of rules, or a flat list of objects, and then it become hard to track. Basically I want insertion ON the tree, but there is so many insertion at random places it makes it turn these solutions useless, because the tree is big.

    It's basically this, too many random and punctual insertion everywhere, kill these ideas in practice.

    A better idea would be to have an addressing on the tree. Which I mention with the observer pattern, which could be seen as a variation of this idea, I already mentioned having "hooks" like delegate to fill. If you have a tree separate from the command, and you append the command based on the traversal of the tree, the tree "emitting" the adresse. In practice I haven't figure out how to implement it, and it still break the legibility, but right now I'm thinking about any easy cope out, like just write the comment on the tree. Also there is an issue with the construction of the tree at editing time, it supposed you know before what the tree shape will be, that's not how game dev works. A lot of similar advice works on a after the fact basis. TECHNICALLY I can do them, PRACTICALLY they hinder the iterations process.

    The issues, as I did another pass today, is that the behavior are unique, which mean it's hard to generalize for all of them (so far), they effectively implement their own domain, which is why they are their own branch in the tree, and even variations of the same "named" behavior can vastly diverge, even along a single character, because story. I'm able to do complex behavior instead of generic behavior like in the sims. But it end up costing flexibility. I thought there would be a easy way to separate stuff, and that clear design pattern existed, but I'm probably wrong, given none have emerged.

    The other issues is I called it a kind of behavior tree, it's not a behavior tree. BT has command on leaf, it's easy to separate them because a sub tree effectively isolate relevant leaf. It's the same for most formalisation like decision tree, or HTN, node are really just high level name and implement sub function that realize the high level task described by the name. I have command at all level, branch are just another kind of complex command, and some command are function which hide their own tree (because I'm no longer going to edit them) or they repeat in the tree.

    I keep seeing the tree as a top down hierarchy, maybe I should look at it as command, with each unique command being a full interpreter of its domain. That is I should consider any tree as their own problem. I have already notice a lot of generic management code are dispersed and could be factorize, maybe once that's done, something will be clear. What I'm going to do is to map visually the whole tree and all exceptions, and look at it as a visual pattern, maybe it's not as bad as I think it is.

    Or I need a radically new way to think.

    Basically it's a me problem:
    - at editing time (dev), the "code tree" proved to be a superior working environnement. If I had to release the code AFTER completion, I would probably do the obvious and snip sub tree away and make nice module. I mean no need to touch it anymore. But for dev time it's the faster method.
    - I'm trying to not create unnecessary tools, and i'm making the java dance to avoid it. In a team environnement that would be the goto method, no question. But I'm not in love with coding and typing and managing file and class, I would not be the programmer for sure.

    You have reading issues, Yagni because:
    - the perception is already a module,
    - it has no need to be swappable, it's complete
    - this part has zero issues and is not a problem

    Reading skill issues:
    - I mention multiple time trying anything else and failing to complete the project. Which lead to the current situation.
    - the project works fine as is, it's going to get completed
    - I'm mostly bothered for future development
    - legible context is essential to track complex behavior
    There is probably a case to be made in which what I want might not be possible. Which is a reasonable conclusion.

    HOWEVER, I keep mentioning I tried that? what are you ignoring that fact.

    Anyway my current conclusion is that I can't have flexibility (file sorting), simplicity and legibility at the same time. Effectively, keeping everything together for legibility and separating them for flexibility are antinomic goal.

    It's deeply irritating to try to convey all informations and people keep ignoring it, since we are talking about chat gpt, it does demonstrate human aren't better, poor context size, being confidently wrong on stated fact, and hallucination. I mean we are judging ai against an idealized ubermensch (chinese vroom!). But we fail to be that ideal.
     
  44. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    You need to store a recipe that ASSEMBLES your subtrees from modules. If you're copying 10000 lines you failed to modularize.

    Yes, you can if subtrees are passed into the tree through parameters.

    For example, MainTree has a constructor.
    "MainTree(DecisionTree action1, DecisionTree action2)", then when making the subtree for character you build specific modules based on a template stored in a scriptable object.

    Trying to insult me will achieve nothing useful for you or your project.

    Because you failing to make it work does not automatically mean the approach is wrong. It only means you failed to utilize it. Meaning you may be lacking skill. So the first thing people are gonna do is dismiss your "I couldn't do it", and explain HOW you can do it.

    In your situation it is highly likely that you've stumbled upon a more complex problem for the first time and struggling. Meaning you need to gain more skill to crack the problem. Every single thing you post screams that. For example, you shouldn't ever have a 10000 lines you can copy, did you know that? Classes should be small. The whole situation is an indication of a HUGE potential problem.

    Yes, flexibility breeds complexity, and simplicity eliminates flexibility. The simplest solutions are inflexible and non-extensible. That's the reason why KISS is a recommended approach. The moment you start throwing around terms like "legibility" and trying to make things perfect and logical and easy to do you're starting to make your codebase more complicated and harder to maintain.

    Welcome to the club.

    It happens because in order to understand your situation it is necessary to have access to your entire codebase and it is impossible to convey all necessary information through words.

    So, to solve your problem instead of forum advice, you'd need to HIRE a programmer, let him have a look at your codebase for a couple of days. And then if the dude is worth anything, likely he'll be able to resolve your problem.

    You'll never be able to convey your situation through words, because that was a long path, you walked through it alone, and only you know ever single detail. People you speak with can't read your mind, they get limited information and fill the gaps. And you provide EVERYTHING, you'll get a "war and peace" sized book, which nobody is going to read.
     
  45. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    I'm not trying to insult you, i'm pointing you to issues with your approach, if you don't read properly, you gonna solve teh wrong problem. Obviously, you fail to understand the problem and exhaust yourself trying to find solution i'm going to dismiss, BECAUSE they don't adress the concern. Any attempt at explaining to you why, fails, so what's the only possible conclusion?

    I'm gonna ignore the modularize things because it doesn't address my concern. You have a hammer, everything looks like nails:

    - I can do it
    - I did do it but rolled back
    - I'm not doing it because editing time concern
    - I will do it if I share the final code
    - I don't need it for myself like you present it, it makes things more complex and not kiss, you see 10 000 and lost your mind.

    The issue is not modularization or not, it's HOW I need the modularization, ie accross the project need, not the file size need.

    Also I'm regularly looking at professional code, the character file in Bungie oni is 17 000 line long, Ken Silvermann's pn3d main file is 20 000 long. Turns out complex project has a lot of content.

    I definetely agree with that, probably for the same reason as you.

    I started using this approach :
    https://www.gamedeveloper.com/pc/analysis-conversation-design-in-games

    I brainstorm a custom version that mixed all similar approach (Like Elan's Ruskin, or Failbetter):

    Code (CSharp):
    1.  
    2. //class quip(-actions?)->generalized to storylets?
    3.     //prerequisites/criterion (list of "quality/facts/context" ranges to unlock it) -> match world state (aka query)
    4.         //topic (group)
    5.         //subjects (multiple possible)
    6.         //opener (if for starting conversation)
    7.         //used (removed from pool once seen or trigger varients)
    8.         //prerequisite (condition: flags, stats, mood...)
    9.         //priority (order of surfacing in limited view windows)
    10.         //rarity weight: chance of surfacing
    11.         //slotting: match type of objects or pattern to be used inside, treat the world state as database to query, These queries search for characters, inventory items, and so on that meet certain criteria and “bind” them to named parameters.
    12.     //contents (display to player)
    13.         //name of the node
    14.         //ID
    15.         //title (seen if selection ui)
    16.         //nested tree, storylets, quips, system, game, level, affordances, cinematic
    17.         //slots: match elements are used inside
    18.         //audiovisuals
    19.         //behavior? (quip):(gesture)
    20.         //options: what you cab do
    21.         //string (text content, can used generator to be modified by stats)
    22.         //varients (if used once, to avoid repeats)
    23.         //-> consolidation, when a group of quip on a subject has been used up, offer a summuary
    24.     //results ("quality" changes)
    25.         //follow up (high priority after specific quip)
    26.         //conveyance metadata: character mood, type of evaluation, factual data (flag or other) ...
    27.         //action?: (modify stats of world or character)
    28.         //goal?: (switch to a goal)
    29.         //effects: spawn something that live in teh world state
    30.  
    31. //storylets:
    32.     //This could be rewritten as “the world state determines what the player is currently allowed to do; everything the player does then updates the world state again.”
    33.     //-> apply teh concept of quip graph search conversation to storylet, adversaries pushing stories to desired storylets with player countering the move by selecting other storylets.
    34.     //quality base-> player selection.
    35.     //salience base-> system selection
    36.     //drama manager that search through storylets to get an ideal story up to (possibly random) specs
    37.  
    38. //layers?
    39.     //- perception
    40.     //- emotion
    41.     //- expression
    42.     //- actions
    43.  
    44.  
    45. //world state
    46.     //key:values[]
    47.  
    I implemented it, and fall on my face. Why?
    I'm so sorry I'm not Emily Short to follow flat rules based system. But I'm me, and must do what I can with what I can do. IE NOT FLAT BROKEN LIST OF MODULE.

    I need stuff to work for me, not for other, else I'll never finish anything.

    Funny is my method works just fine. I just want separation in file that make sense, THAT'S IT.

    It's okay if it's not possible
     
  46. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    It is an important concern though.

    Code should be split into small pieces that do not depend on each other. That way when you alter a single piece it won't affect half of your project. That's how principles like DRY appear.

    "Modularizing" does not mean everything should be wrapped into a class, etc. It does mean that things should be split into manageable swappable interchangeable fragments. Those fragments could be functions.


    Here's the lesson for you: you should try not to follow principles fantically. You keep quoting the same fragment, and treat it as an absolute truth.
    The issue is that conversation is not exactly code. It is closer to data. You're applying a wrong principle. The approach described in the article is fairly good.

    So the issue about unstructured jumps in programming do not directly apply to conversation. In case of conversation data you should be asking yourself "are hyperlinks bad and should they be avoided?" because that's what a jump in conversation is.

    The reason why people avoid goto in programming is because they want to avoid this scenario:
    This is unmaintanable in modern age. However, avoiding goto completely is a bad idea, because there are scnearios where it is useful. A fairly common approach is using this sort of thing when exceptions are not available:
    Code (csharp):
    1.  
    2. resource1 = createResource1();
    3. if (!resource1)
    4.     goto cleanup;
    5. resource2 = createResource2(resource1);
    6. if (!resource2)
    7.     goto cleanup;
    8. ....
    9.  
    10. cleanup: //goto label
    11.   releaseResource2(resource2);
    12.   releaseResource1(resource1)
    13.  
    So the idea is to make jumps structured.

    When generalizing conversation a good idea is to treat it as a filesystem. Or a web page.
    You open a top level topic, you get sub-links going deeper, except they can have conditions assigned to them, which will determine where those are appear. You can also terminate the conversation, which would be equivalent to exit(), or you can go up several levels, using an equivalent of "../" or "../../" in filesystem. This will be maintainable. What's more, you'd be able to extend it and insert your own branches, as long as every dialogue retain unique address.

    In the aritcle you listed, what happened is that the author flattened the tree and turned it into a format comparable with a database record. But that's the extent of it. There are no unstructured jumps there. Only nodes, their parents and prerequisites for them to trigger.
     
    Last edited: Mar 18, 2023
  47. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    And that's still not a concern, because you are applying a dogma, ie you respect the law but not the spirit of the law. I told you I did that, and failed. Experience being better than theory, but I can still understand WHY I'm told that and made a new implementation when the dogma fail, that is:
    To be frank the number of if else was never a problem. Though if I can better encapsulate them that's still a win.

    On the practical scope of a dev, which isn't linear and is highly iterative, If are simple insertion, you don't spend one chunk of time adding all if in one go, and the structure is rather easy to grasp and navigate. That mean that constantly modifying the tree don't create problem, finding problem is equally easy, because if encapsulate behavior neatly, which also mean they are easy to move around.

    Basically you have a few recurring mistakes that can happen:

    - wrong logic checks, if enforce strong ordering, so that's easy to localized, you can follow step by step in the branching and avoid part of the code you don't need to look at.

    - wrong ordering, if encapsulate logic in their body, fold and copy paste to reorder, copy paste is generally frown, but that's not the same type of copy paste (the laws vs the spirit of the laws).

    - wrong logic in the body, since it's easy to localize, and that logic are self contained such that the scope doesn't bleed outside the if body.

    The real benefit of if tree is the ordering in a branching structure, it has the same benefit that function or class for encapsulating logic, less so for encapsulating data BUT you can cheat by leveraging Lambda functions to wrap the If block to get some locality of variable (but not permanence of variable like object, which mean each frame you lose data), and you gain the function to break out at any point of the If block without going out the entire tree.

    If tree are typically bad in other programming context, where a simpler alternative generally always apply, and the context (edition, iteration, scope) are different.

    LIVE AND LEARN!

    The irony of someone telling me dogma despite me providing context that show it fails in this specific practice. That's hammer vs nail issues, not everything is a nail, you should nail that.

    :rolleyes: What I can say except facepalm, i'll try anyway:

    You are wrong because you make the wrong assumption. It's like you fail to understand abstract concept and get bogged down by details. The first issue is I use goto as a reference, that is i'm NOT talking ABOUT goto, I'm talking about unstructured jump.

    Unstructured jump is about the FLOW of logic, it's not about the "code" as a "tangible object", it's about a set of rules or command with no explicit ordering. A tree is an explicit ordering.

    Ie rules set a state, then the system figure out which next rules satisfied the condition, that mean the flow, ordering, is obfuscated by one indirection (the state) where there is no direct relation to the previous rules. ie rules are independent in format EVEN THOUGH there is an implicit ordering in their prerequisite, that is a rules can only fire IF a previous rules set a required state, I hope there is enough redundancy in this laborious explanation that you get it.

    I told you it arise from experience with this code, I told you I did the data base method, not explicitly, but that's what abstract reasoning are about. Look I'm not trying to insult, you, I'm trying to point at flaw in your reasoning, that you may not and probably will never adress, because this conversation is on repeat.

    ANYWAY, again the solution was to listen to @TonyLi, break things further:

    I came to realize something, It's not a character behavior code, it's a SCENE behavior code. The equivalent would be branching dialog sequence, in other game, except of text you have whole actions and behaviors. Joint actions between character and options, are decided by gameplay events, during phases of the sequence. Obviously that was dangling every time I told about why it was different from character behavior, but I hadn't realize the implications yet.

    It change the perspective on how to organize the code, it's a scope problem. Some data currently attributed to character, aren't for the character, but describe the SCENE states or transition from scene to another. That is SCENE contains character's behaviors, but aren't character behavior themselves, they direct character, and thus need specific encapsulation. That's why there was many characters within some branch of behavior, because it's misnamed and mis categorized.

    Let's look at a mocked bath mis categorized "behavior", not using a joint character scene (no multiple character at the same time), assuming it's the yandere simulator game as a reference:

    Code (CSharp):
    1. 0. is triggered by being dirty events
    2. 1. go to communal bath
    3. 2. go to locker
    4. 3. change cloth to swimsuits
    5. 4. take the bath
    6. 6. go to locker
    7. 7. change back to normal cloth
    8. 8. exit the communal bath
    This would constitute the basic behavior.

    Context:
    The true purpose of the bath scene isn't to make the character realistic, but to offer gameplay opportunity in the game of social stealth and manipulation, it's the "level". That is the Dirty events is created as opportunities to move or remove characters from a place to another place. For example, the locker allow you to tamper with character belonging and do action like put a letter, stole the phone, stole the cloth, plant evidences, etc ...)

    Actual (mocked) code is more structured like that, the (isX) denote easily added "if-cards" to create variants per character/persona (not joint behaviors) :

    Code (CSharp):
    1.  
    2. 0. is triggered by being dirty events
    3.  
    4.    (is rich girl: rage 1mn about the clothes, change mood to angry)
    5.  
    6.    (is fragilePersona: start crying, change mood to sad)
    7.  
    8.    (is nemesis: look around suspiciously, mood change to vigilance)
    9.  
    10.    (is idiot AND judgementalPersona nearby: judgemental.talk, play embarassed animation)
    11.  
    12. 1. go to communal bath
    13.  
    14.    (is rich girl: call her bodyguard to follow her on the way)
    15.    (is rich girl AND is arrived at communal bath: the guard get posted at the entrance, intimidate anyone passing nearby)
    16.  
    17.    (is nemesis AND arrive at communal bath: slowly push the door, scan the room, close the door carefully, tapped a bell to the door)
    18.  
    19. 2. go to locker
    20.  
    21.    (is rich girl: lament the cloth)
    22.  
    23.    (is nemesis: open the locker carefully, double check the environement and inspect inside the locker)
    24.  
    25. 3. change cloth to swimsuits
    26.  
    27.    (is rich girl: look at the mirror to flatter herself, change mood to normal)
    28.  
    29.    (is nemesis: tapped a bell inside the locker, pick the knife, close locker's door slowly)
    30.  
    31.   (is idiot: look at the mirror do funny face and poses for a while)
    32.  
    33.  
    34. 4. take the bath
    35.  
    36.   (is fragile: cry during bath)
    37.  
    38.   (is nemesis: submerge whole body to hide the knife)
    39.  
    40.   (is idiot AND time remaining is small: do hurry bath)
    41.  
    42. 6. go to locker
    43.  
    44.   (is nemesis: removed the tapped bell from locker)
    45.  
    46. 7. change back to normal cloth
    47.  
    48.   (is nemesis: removed the tapped bell from door, open slowly the door, scan the environement)
    49.  
    50. 8. exit the communal bath
    51.  
    52.   (is rich girl: the guard follow her to next place)
    53.  
    54. MISC interruptions and branches.
    55.  
    56.   (is nemesis AND bell sound AND 3 < phase < 7: Speech("I was expecting you"), change to fight mode)
    57.  
    58.   Letter at locker:
    59.  
    60.       (is nemesis: dismiss and toss to trash)
    61.  
    62.       (is rich girl: mood set to angry)
    63.  
    64.       (is fragilePersona: mood set to scared)
    65.  
    66.       (is idiot: Mood set to concerned)
    67.  
    68.   Phone stolen: [...]
    69.  
    70.   Evidence planted: [...]
    71.  
    72.   Clothes stolen: [...]
    73.  
    74.   Player detected: [...]
    75.  
    76. end.
    77.  
    Using the perspective of SCENE scope rather than CHARACTER scope, this bath SCENE, should be encapsulated as its own objects with it's own local variables and method that manage the flow. SCENE are self contain context.

    This scope issue reveal that, many old character behavior where part of a common scene, that is when I needed context to track multiple behavior, have joint hard coded behavior, and many of single use variable, they were scene scope elements. Having scene as concept ties up these thing together.

    Which mean I can now introduce new concepts to generalize the scene as structure (yandere simulator as an example):

    ROLES: these are scene level behavior, character are elected to be in a role during the scene that define their behavior within that scene. For example you can have a character see a corpse, go into the REACT TO MURDER scene, if no one has taking the role, get set to REPORTER, then find a teacher to investigate, said teacher taking the role of INVESTIGATOR. Then call the police if evidence are found. Character no longer need contain behavior of a scene, they will take a reference to the scene and follow the script.

    PHASES: Basically it's the ordering of behavior, controlled by flow variable, in actuality it's the if tree. For example the REACT TO MURDER scene, would have approximately: react to corpse, find teacher, follow teacher, wait for teacher, exit the scene.

    TRACKS: Basically it's the way to encode the multiple phases in a scene, it's likely that phases are tied to roles, TRACKS would be parallel phases per role, it is to be noted, it's possible for character to change role mid sequence (for example, a fight can have people waiting and one person attacking, rotating attacking and waiting role).

    SCENE STATE: track data and flow control for the scene.

    SCENE METHOD: The scene can have extra computation to control the flow of a scene. For example rotating who is attacking in a fight.

    INTERRUPTIONS: basically the exit of the sequence, lead back to the common simulation or another scene.

    Phases and tracks are also the basis for addressing, which allow to implement per character override of behavior like in the bath scene above. Also scene being distinct entity help coordinate agents more easily, for example, there is ONLY one reporter at the time in REACT TO MURDER scene, instead of doing code judo, when a character enter the scene, it checks if reporter slot is already taken, previously, the ai manager was used as an overall container, which lost the context.

    There is no real way to define the scope of a scene from another scene or even tracks and phases, or from generic social practice, the bath scene is a social practice or a story scene? The difference is left to the author to decide. It's possible to have an uber scene that could be break into sub scene, but is sub scene can be a concept? Scene is a useful encapsulation of behavior anyway.

    Using these observation and generalization, I can break up and reorganize the code into a new architecture where I break responsibility further:

    - The global ai manager is stripped from some responsibility and is merely the manager of sub module. It may hold global generic behavior (like talking), but no longer track agents.

    - The social area objects, hold by ai manager and track characters. Basically they hold area based "scene" called "social practice" (idea borrowed from Versu), for example the school hold practice like going to class, practicing sports, doing club activity. Another social area could be the mall, where "going to class and doing club activity" do not make sense. This represent the basic level background simulation.

    - A story manager, which hold the structure of scenes that implement the progression of plots based on player's action and character states. It might inject Scene in social area to perform. For example recording evidence in the REACT TO MURDER scene would be stored here.

    - A character sheet object, that implement the basic data of a character, such as appearance, stats and specific animations.

    - A character script objects, that encapsulate the character sheets and the scene override of that character (like isX in the BATH example). The motivation in separating with sheets, is to be able to reuse character in different story.

    - An ACTOR agents, there is no longer a character object, actor takes a sheets to define their appearance, the stats to perform actions, and animation to display behavior. They also have a set of generic behavior, such as moving and playing animation, and hold the mutable states of the character. But the behavior are now injected by higher structure such as story, character scripts and social area objects, this can be implemented in many way (ECS and all), but for now I just keep a reference to these structure and call their behavior function on the character's state. This mean put the character in a mall or school, at a certain story point, and it would behave accordingly without modifying the actor.

    This makes editing (authorship) collected in a a few places instead of many characters. First you start with defining character or you set social areas, then you write up the story behavior, then you specify character override relative to the story.
     
    Last edited: Mar 24, 2023
  48. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,566
    Improve your programming skills.

    You're describing the very same thing I've been repeatedly trying to explain to you back in february.
    https://forum.unity.com/threads/character-ai-code-architecture.1403725/#post-8829733

    Remember what I told you about sims and feats? Well, here you go. Things that happen are external to the character. "is rich girl" is a sims feat.

    Now turn the whole thing into a tree, and externalize each branch into a feat, uncoupling branch from the scene, and you'll get what I'm talking about here:
    https://forum.unity.com/threads/character-ai-code-architecture.1403725/#post-8885847
    Also, study renpy, and the way dialogues are organized in skyrim or in neverwinter 2, where dialogues are treeds with nodes where each leaf can have condition and action associated with it. Again, same thing.

    Anyway. By now, you've spent a month of this instead of finishing it, and I've spent inordinate amount of time timing to provide info. You aren't listening to anything and keep throwing accusations instead.

    I'm not paid for this and have better things to do.

    Have fun.
     
    Last edited: Mar 24, 2023
  49. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    This has run its course. Closed.
     
    dnorambu and neoshaman like this.
Thread Status:
Not open for further replies.