User Tag List

Page 3 of 4 FirstFirst 1 2 3 4 LastLast
Results 21 to 30 of 32

Thread: Message system discussion

  1. #21
    The Time-Loop Continues ZC Developer
    Gleeok's Avatar
    Join Date
    Apr 2007
    Posts
    4,815
    Mentioned
    259 Post(s)
    Tagged
    10 Thread(s)
    vBActivity - Stats
    Points
    12,933
    Level
    33
    vBActivity - Bars
    Lv. Percent
    23.44%
    Quote Originally Posted by DarkDragon View Post
    Gleeok, can we do something like this:

    There is a list of game objects (which I will cause Objects, for lack of any creativity) that can have scripts attached to them. An initial list of Objects are
    1. the game itself;
    2. the screen;
    3. Link;
    4. npcs;
    5. items;
    6. weapons;
    7. combos (freeform or otherwise).

    Each Object maintains
    - any number of scripts, each of which can contain any number of callbacks;
    - local variables associated to that Object

    The game engine, and scripts, can send a message to either a specific Object (via a pointer to that Object) or broadcast a message to all active Objects.
    If multiple Objects would receive a message, they receive them in a well-defined order (for example, in the order listed above, with scripts associated to the game getting first dibs, then screen scripts, etc). Each callback returns whether to continue processing the message, or to stop. Each callback runs in its own execution context as described in my first post.

    You suggestion to start with just CB_ON_UPDATE and CB_ON_DRAW sounds fine to me. We can work out the details of WaitFrame() and WaitDraw() within callbacks, Object pointers and variables, execution contexts, etc. for just these two basic messages, and build up from there.
    As a good jumping off point I was planning on Screen and Global scripts, or "Objects," first then going from there. The first script system I wrote was over-engineered and as a result was crap to work with and use; the second time I learned my lesson and it was much simpler. Forcing scripters to use objects (read: classes, member ptrs, virtual, inheritance, etc.) for everything is not a good start I don't think. Tell me if you think I'm wrong here, but whenever we can do a simple procedural style interop I'd go with that.

    The simplest things to add (and immediately support) right now are global callbacks--Link is just a namespace so he falls into that category as well--everything else object related needs a bit of integration into ZC, and npcs need a slight refactoring first. Also doing the bindings and all that junk for them so I'll call that phase 2.

    The way I'm doing it right now is this: If a script object defines an instance callback then it gets called, if not then the engine will ignore it. For example:
    Code:
    class MyGlobalScript
    {
      int myTime = 420;
    
      void OnDestroy() { //this callback is defined, so it gets called by the engine.
        //last call for alcohol
      }
    }
    In this example maybe the scripter doesn't care about it being updated, or drawn, or anything else besides what happens when it is destroyed, so that is fine. It still exists and other scripts can access it the same, or whatever else. Did you have something better in mind?

    I don't like the idea that any object can have any number of scripts though, that sounds very complicated and bad. Can you give an example?

    Also Waitframes(), contexts, and callbacks are already working. I do need to implement an intermediate pass over preprocessed script code (hopefully without any major lexing) as a next thing I do though. Modifying angelscript is not so easy for certain things, and I wasted a bunch of time in that when I should of just done it separate... :/
    This post contains the official Gleeok seal of approval. Look for these and other posts in an area near you.

  2. #22
    Administrator DarkDragon's Avatar
    Join Date
    Oct 2001
    Posts
    6,228
    Mentioned
    70 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    11,025
    Level
    31
    vBActivity - Bars
    Lv. Percent
    8.16%
    As a good jumping off point I was planning on Screen and Global scripts, or "Objects," first then going from there.
    Sounds good to me. In fact it may make sense to implement AS for Screen and Global scripts, and then release a public beta letting users play around with it, and gather feedback we can use to flesh out other scriptable things.

    Forcing scripters to use objects (read: classes, member ptrs, virtual, inheritance, etc.) for everything is not a good start I don't think. Tell me if you think I'm wrong here, but whenever we can do a simple procedural style interop I'd go with that.
    I'm not sure what you mean? Under the hood, the game engine will need to keep track of the "list of scriptable things" and have a way for scripts to reference them (whether this is handles, pointers, integer IDs, or whatever). I don't care much about the details of how this is done, though having a class for e.g. items, with built-in member variables that are common to all items, does make sense to me.

    In this example maybe the scripter doesn't care about it being updated, or drawn, or anything else besides what happens when it is destroyed, so that is fine. It still exists and other scripts can access it the same, or whatever else. Did you have something better in mind?
    Sounds good to me.

    I don't like the idea that any object can have any number of scripts though, that sounds very complicated and bad. Can you give an example?
    Sure, supposed you have a screen for a dungeon boss. You have one screen script in charge of controlling the boss, one that is in charge of some environmental effects (lava that hurts link and teleports him when he falls in), and one that handles some ancillary graphics (creating clouds of steam that change shape and wander around the screen). Instead of writing a Franken-script that tries to do all of these things, you split up the unrelated stuff into independent scripts each with their own independent callbacks.

    This has several advantages:
    1. Smaller self-contained scripts are easier to work with than giant scripts that try to do a lot of unrelated things;
    2. Smaller self-contained scripts are easier to mix and match (you can reuse the vapor cloud script on a different screen that doesn't have the boss);
    3. On a related note, smaller self-contained scripts can be independently packaged and shared (i.e in the QDB).

    Even for e.g. items it is useful to be able to split up callbacks between several scripts. For instance you might want one script that handles animating an items, and another that is in charge of the item use behavior, since it seems commonplace for users to want to be able to mix-and-match the two parts of an item without having them tied to each other.

  3. #23
    Keese
    ZC Developer

    Join Date
    Jan 2007
    Age
    34
    Posts
    52
    Mentioned
    27 Post(s)
    Tagged
    1 Thread(s)
    vBActivity - Stats
    Points
    778
    Level
    9
    vBActivity - Bars
    Lv. Percent
    78.95%
    Are the local variables associated with each object going to be like the ->Misc[] arrays currently in use, or will they be different for each object class, or will it be more like a self.anyNameYouWant = 30; lua/javascript kinda deal?

  4. #24
    Administrator DarkDragon's Avatar
    Join Date
    Oct 2001
    Posts
    6,228
    Mentioned
    70 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    11,025
    Level
    31
    vBActivity - Bars
    Lv. Percent
    8.16%
    I imagine it will be a mix of pre-defined variables with game engine meaning (like Tile, etc) and user-defined variables. I hope Misc[] goes away, it's a crude workaround from the days where all data associated with an FFC had to be defined at compile time.

    There is an important but subtle distinction between (a) variables associated to an object (the Game, an item, etc) and (b) variables associated to a script attached to the object. I suppose we need support for both.

  5. #25
    The Time-Loop Continues ZC Developer
    Gleeok's Avatar
    Join Date
    Apr 2007
    Posts
    4,815
    Mentioned
    259 Post(s)
    Tagged
    10 Thread(s)
    vBActivity - Stats
    Points
    12,933
    Level
    33
    vBActivity - Bars
    Lv. Percent
    23.44%
    Quote Originally Posted by DarkDragon View Post
    Sure, supposed you have a screen for a dungeon boss. You have one screen script in charge of controlling the boss, one that is in charge of some environmental effects (lava that hurts link and teleports him when he falls in), and one that handles some ancillary graphics (creating clouds of steam that change shape and wander around the screen). Instead of writing a Franken-script that tries to do all of these things, you split up the unrelated stuff into independent scripts each with their own independent callbacks.

    This has several advantages:
    1. Smaller self-contained scripts are easier to work with than giant scripts that try to do a lot of unrelated things;
    2. Smaller self-contained scripts are easier to mix and match (you can reuse the vapor cloud script on a different screen that doesn't have the boss);
    3. On a related note, smaller self-contained scripts can be independently packaged and shared (i.e in the QDB).

    Even for e.g. items it is useful to be able to split up callbacks between several scripts. For instance you might want one script that handles animating an items, and another that is in charge of the item use behavior, since it seems commonplace for users to want to be able to mix-and-match the two parts of an item without having them tied to each other.
    Ah, I see what you are saying. I did think the same thing except our solutions were different. Instead of multiple object script contexts I was opting for single object context and general way for scripts to create other contexts if they want to. ..I guess they both are OK but there is downside:

    Code:
    void Callback_or_Whatever()
    {
      //get script attached to object
      IScript@ obj = [email protected];
      if(obj !is null) {
        // access script object here
      }
    
      // Or... multiple scripts
    
      for(int i=0; i < ffc.NumScripts; ++i) {
        IScript@ obj = [email protected][i];  // check for specific script type here... or what?
        if(cast<MyScript@>(obj) !is null) { 
          // it's the battering ram script part so ignore it..
        }
        if(cast<AnimationController@>(obj) !is null) { 
          // change the animation..
        }
      }
    }
    I don't know. AS supports composition and virtual inheritence already so I just did the simplest thing. We'll play around with it.
    This post contains the official Gleeok seal of approval. Look for these and other posts in an area near you.

  6. #26
    The Time-Loop Continues ZC Developer
    Gleeok's Avatar
    Join Date
    Apr 2007
    Posts
    4,815
    Mentioned
    259 Post(s)
    Tagged
    10 Thread(s)
    vBActivity - Stats
    Points
    12,933
    Level
    33
    vBActivity - Bars
    Lv. Percent
    23.44%
    Okay, I'm looking at it right now. I need to add two major components and three minor ones and then it should be ready for you to mess around with. You'll only have access to Global functions, Logging, and Link variables right now, but hey. Kind of busy this week, but I'll see what I can do.
    This post contains the official Gleeok seal of approval. Look for these and other posts in an area near you.

  7. #27
    Administrator DarkDragon's Avatar
    Join Date
    Oct 2001
    Posts
    6,228
    Mentioned
    70 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    11,025
    Level
    31
    vBActivity - Bars
    Lv. Percent
    8.16%
    I guess they both are OK but there is downside:
    Is there a need to check for "script types"? If scripts are just a collection of callbacks, presumably you just need to check scripts for the callback you're looking for, and invoke the method if it's found.

    Okay, I'm looking at it right now.
    Awesome, looking forward to it!

  8. #28
    The Time-Loop Continues ZC Developer
    Gleeok's Avatar
    Join Date
    Apr 2007
    Posts
    4,815
    Mentioned
    259 Post(s)
    Tagged
    10 Thread(s)
    vBActivity - Stats
    Points
    12,933
    Level
    33
    vBActivity - Bars
    Lv. Percent
    23.44%
    Maybe I'm still misunderstanding... ..If objects have arrays of scripts, then you'd have multiple callbacks even though it's the same object. If a script needs access to variables from another script it's the end user that has to sort through them, which is why I think it's needlessly complex. Does composition do what you are suggesting? Eg;

    Code:
    class Foo
    {
      Bar@ bar; // thing a) subscript of this object.
      Baz baz; // thing b) Similar to bar, but we'll just handle it ourselves without the overhead of another script context.
    
      Foo() {
         bar = Game.CreateSomeScriptContext(..);
         bar.parent = this;
      }
    }
    This post contains the official Gleeok seal of approval. Look for these and other posts in an area near you.

  9. #29
    Administrator DarkDragon's Avatar
    Join Date
    Oct 2001
    Posts
    6,228
    Mentioned
    70 Post(s)
    Tagged
    0 Thread(s)
    vBActivity - Stats
    Points
    11,025
    Level
    31
    vBActivity - Bars
    Lv. Percent
    8.16%
    I understand what you mean: if scripts are classes independent of the objects they are attached to, it is awkward to access or create variables on the objects themselves, rather than on the scripts.

    This is also a problem currently with ZScript, where users make use of the Misc array to store data at the object level.

    I'm not sure there's a clean way around it, though. One solution is to have objects (the game, screen, Link, items, etc.) maintain a key-value store that scripts attached to these objects can read and write from (a la JavaScript), and as you say it's then the user's responsibility to make sure that different scripts do not trample on each other when trying to share use of the same variables. If I understand correctly, you are suggesting another: there is a "master" script for each object, which can contain subscripts. Only the master script can create variables attached to the object (i.e., accessible from other scripts not attached to that object, and persisting after scripts finish executing and/or are unattached)? In ZQuest how do I specify which script is the master?

    Maybe it is helpful to discuss a concrete example. Let's say I want three scripts attached to a certain screen:
    - a miniboss script;
    - a lava script (checks if Link steps on lava, and punishes him when he does);
    - a purely cosmetic "vapor" script.

    1. All three want to listen and respond to the OnUpdate() callback, and do independent things inside that callback.
    2. The lava script doesn't need write access to any of the Screen's variables. It passively listens for messages and checks Link's position against the Screen's Combo array each frame.
    3. The miniboss script and vapor script both want to write persistent state to the screen: the miniboss wants to keep track whether the boss has been killed or not (once killed it stays dead) and the vapor script wants to store the vapor cloud's current position, so that it persists if Link leaves and reenters the Screen.
    4. The miniboss script wants to be able to read the vapor script's stored position (maybe the boss runs towards and hides in the vapor when it gets too hurt).
    5. Once the boss dies, the vapor on the screen stops (the vapor script detaches from the Screen and no longer receives any new messages). Maybe this is done by the miniboss script sending the vapor script a Kill message, or by directly telling the Screen to detach the vapor script... I'm not sure.
    6. Ideally, it is possible for the user to achieve all of this by just going to Screen->Scripts in ZQuest, and clicking "add script" three times and pointing to three different script files written by Moosh, without needing to do any additional coding.

    What's the simplest setup that would allow for this kind of interaction?

  10. #30
    Keese
    ZC Developer

    Join Date
    Jan 2007
    Age
    34
    Posts
    52
    Mentioned
    27 Post(s)
    Tagged
    1 Thread(s)
    vBActivity - Stats
    Points
    778
    Level
    9
    vBActivity - Bars
    Lv. Percent
    78.95%
    Here's how I'm imagining the system:

    Global:

    • We have a global persistent key/value store for miscellaneous data. This can be used to store data between instantiations of the same object if needed.

    Objects:

    • Every object can be interacted with by its class. So a screen object has methods and variables that make sense for Screen, etc. (Like the Screen-> we have now).
    • Every object exposes a scripts array/list/whatever listing all the scripts it has attached to it. Scripts can be added/removed dynamically, but the added/removed scripts aren't saved persistently across instantiations of the object.
    • Every object has a publicly accessible key/value store. Again, this isn't saved persistently across instantiations of the object. This bit is nice to have, but it isn't particularly important that it's done right away, or at all.
    • The Screen object, and others that make sense to, may optionally have a persistent data store.
    • Every object has a void receiveMessage(string message, args...) method. The object just passes the message on to all of its scripts.

    Scripts:
    • Each script has a public pointer to its attached object and its own name.
    • Scripts can be moved between objects, but can't live on unattached. (Though there will be a global Game object for global scripts.) Every script can have a destructor message for when its attached object dies (possibly letting it move to another object before it disappears.)
    • Every script has a vod receiveMessage(string message, args...) method which adds a pair<Script, Message> to the global queue. The queue is run through several times a frame - during Waitdraw(), Waitframe(), etc. Basically, any time the main program stops to send the built in messages, we run through the queue first. Messages can be appended to the queue by messages started from the queue, and they will still execute during this time step.
    • Every script has a public bool hasMessageHandler(string name).
    • Scripts don't need a key/value store, since they can just make variables as needed. Though it might be useful for insterscript communication?


    So, for your scenario:

    The lava script is attached to the screen, and otherwise doesn't interact with anything.

    The vapor script:
    • On instantiation, the script checks if it should be run. This is either by checking the global data store ("noVapor:" + dmapid + ":" + dscreenid), or the persistent screen data store if we go that route ("noVapor").
    • The script has a custom kill() message, which detaches it and marks the noVapor variable as above.
    • In the update message, it stores "vaporX" and "vaporY" in the screen's temporary data store.

    The boss script:
    • Creates the boss when you enter the room. It can make use of the engine's existing boss death flags and such to manage this.
    • When it detects the boss's death (through the destructor, probably), it'll send the kill message to the vapor script.
    • It reads the screen's temporary data store for "vaporX" and "vaporY" to move to. If they're not present, it just doesn't execute that attack pattern and moves on to the next.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
About us
Armageddon Games is a game development group founded in 1997. We are extremely passionate about our work and our inspirations are mostly drawn from games of the 8-bit and 16-bit era.
Social