Menu

the authoritative(?) plan for mixing

Mixing
2003-09-05
2003-09-12
  • steve breslin

    steve breslin - 2003-09-05

    When we make design decisions, we need to keep as first priority the ease of the user.

    Here's a model for liquid mixing which I think the user will find easy to understand and easy to use:

    The Liquid class handles both "pure liquids" and mixtures. Mixtures are not special: the only thing that differentiates "pure liquids" from mixtures is that the component list for "pure liquids" points to one component and the component list for mixtures points to more than one component.

    Now when we refer to "the liquid" we mean the game object, which is a manifestation of the Liquid class. When we refer to "the component(s)" we mean an abstract data object which never gets manifested in the game (either directly or as a superclass of another object -- i.e., LiquidComponent does not inherit from Thing, nor is it a mix-in class).

    All Liquid game objects are composed of at least one component. For every Liquid object there is a component vector or lookup table. The vector or lookup table records which components comprise the liquid, and their relative volumes. The sum of the components' volumes (as recorded in the vector or lookup table) equals the volume of the liquid game object. Note that the LiquidComponent objects do not have a volume property: the same LiquidComponent object may be an element in any number of Liquids' component vectors, so the volume is kept track of by the Liquids, not by the component objects.

    LiquidComponent objects are barebone, designed to define only basic properties. The definition for LiquidComponent might look approximately like this:

    LiquidComponent: object
        density = 1
        opacity = 0
        toxicity = 0
    ;

    Note especially that the Liquid class defines all the methods. If we want to have a poison, we define all the poison code in Liquid, not in LiquidComponent: Poison. This way we don't need to worry about passing actions which the liquid is performing or receiving onto its components. The liquid handles all its actions.

    There should be no need to subclass Liquid. All game-object liquids can inherit directly from Liquid. The Liquid class defines all methods associated with all pure or mixed liquid types. If the user wants to add a new behavior (such as ignite), the user would be encouraged to modify Liquid and add the verb handling (action processing) code to Liquid, rather than subclass Liquid as BurnableLiquid. A crucial part of this new action processing would be the verification stage, which would check the component vector of the current liquid for an instance of BurnableComponent, which the user would also define.

    The component or components are kept track of by the liquid in case any library or user-defined methods want to find out which components are in a liquid. But any "special processing" (associated with special combinations of components in a liquid for example) is the domain of the liquid or the domain of optional user-defined chemistry ops, which are checked when mixtures come into contact.

    By default, when components are mixed, the default chemistry op controls the mixing process. For example, the default op has a method which "averages" the components' properties and applies the result to the resultant Liquid. (For example: "poisonComponent" has a toxicity of 10, and "waterComponent" has a toxicity of 0. A 1 liter liquid whose component is "poisonComponent" mixes with a 1 liter liquid whose component is "waterComponent." The combined liquid is assigned a toxicity of  5.) Whenever the library's default property-averaging is insufficient, the user can make a chemistry op which modifies this property averaging.

    Whenever any other default mixing processes need overriding, the user is encouraged to make a custom chemistry op. One scenario might be to replacing a multi-component liquid with a single-component liquid. A chemistry op might do non-liquid related stuff as side effects, too, and would be responsible for setting up any daemons associated with the liquid, such as a daemon which makes an emulsion separate.

     
    • steve breslin

      steve breslin - 2003-09-05

      Question: is it useful or necessary for liquids to keep track of their components? Since components just define properties which are then assigned to the liquid, it might not be necessary. Probably a good idea to keep track of components in case a user defined special chemistry op will want to know; but I'm curious if it's necessary for the base library to keep track at all.

      -----------------

      How should the properties of liquids be initialized. How will the user place liquids in the game and set their component list? Could the user just set the component list of the liquid and then we run the chemistry op for the liquid as a preinit, there initializing the liquid's components based on the component list (as if we're combining the components in a mixing action at the beginning of the game)?

       
    • steve breslin

      steve breslin - 2003-09-05

      >There should be no need to subclass Liquid. All game-object liquids can inherit directly
      >from Liquid.... If the user wants to add a new behavior (such as ignite), the user would
      >be encouraged to modify Liquid and add the verb handling (action processing) code to
      >Liquid, rather than subclass Liquid as BurnableLiquid.

      An alternative (which I don't like as much for some reason) is to give Liquid a 'failure verification' and BurnableLiquid a 'success verification' and action routine. This is somewhat built on the framework of the main adv3 library. For new actions the user will probably also want to modify Thing, and give it a 'failure verification' too.

      I think it would be fine to keep everything in Liquid though, rather than have to worry about subclasses of Liquid.

       
    • steve breslin

      steve breslin - 2003-09-12

      The default mixer op (i.e., the mixer op class) will look something like this:

      mixer: object
      // what's a nicer way to handle the following prop?
          /* the following list property is used to
           * determine which mixer object should handle
           * the given combination. By default this list
           * is empty, meaning that any mixture which does
           * not have a special mixer object uses this
           * general one.
           */
          appliesForMixturesContainingAllOf = []

      // if the user wants to entirely replace the typical
      // combination with an entirely new object,
      // this method is modified:
          initializeMixture(newLiquidObject,
                               comp1, volumeComp1,
                               comp2, volumeComp2, ...)
          {

      // each of the following will call another method
      // defined by the mixer (modifiable by subclasses of
      // the mixer):

      // compute volume & apply it to new liquid
      // compute alpha & color & apply it
      // compute adjectives and nouns
      // compute density
      // etc.
          }

      // if the user wants to customize how the volume
      // of the new mixture is determined, the following
      // method is modified:
          computeVolume(...) {} // etc.
         
      // if the user wants to assign special nouns and
      // adjectives when a particular mixture is created,
      // this method is modified:
          computeNounAndAdjective(..) {} // etc.
      //etc.
      ;

       

Log in to post a comment.