Messing about with inventory panes

Hey :D

I've been playing around with the character creation system for my latest game. In this game, the character classes are objects you can pick up, and when you use the "Wake up" command, all the ones currently in your inventory have their stats applied to the player.

As part of this, I've done some mucking about with the JS function updateList. I'm sure nobody will want to use this as it is; but my modified updateList might be useful as a base for building other things. Basically, the inventory pane is renamed "character creation", and the "Places and Objects" pane is hidden. Instead of being added to a list in the sidebar, it creates a <div/> for each available object.

The default updateList clears the pane and then fills it with the current items every time you refresh. But as chargen is a trippy dream sequence ("pick yourself from the images swirling around you") I decided to make the items swirl around the screen. So I modified it to only create new elements for new items, and to remove them when you can no longer see them. This allows me to give these divs to the jQuery .spiral animation plugin, and not have them be destroyed and recreated every turn.

(function() {
  var realUpdateList = updateList;
  startCharGen = function () {
    $("#inventoryLabel .accordion-header-text").text("Character Creation");
    $("#placesObjectsLabel,#placesObjectsAccordion").hide();
    updateList = function (listName, listData) {
      console.log("Update called for "+listName+"\n");
      if (listName == "inventory") {
        console.log("  Calling real list\n");
        realUpdateList(listName, listData);
      } else {
        console.log("Is this called?\n");
        $(".cc-spiral").attr("toremove", "true");
        $.each(listData, function (key, value) {
          var data = JSON.parse(value);
          var objectid = "cc_object_" + data["ElementId"].replace(/\W/g, "");
          console.log(" searching for "+objectid+"!\n");
          var item = $("#"+objectid);
          if (item.length » 0) {
            console.log("  found element "+objectid+"!\n");
            item.removeAttr("toremove");
          } else {
            console.log("  Not found element "+objectid+"!\n");
            item = $("«div/»", {class: "cc-spiral", id: objectid}).appendTo("#gameBorder");
            console.log (item);
            console.log ("Did that work?\n");
          }
          item.data(data).html(data["Text"]);
        });
        $(".cc-spiral[toremove]").each(function (i) {console.log("Removing element "+this.id+"!\n");} );
        $(".cc-spiral[toremove]").remove();
      }
    };
  };
  endCharGen = function () {
    $("#inventoryLabel .accordion-header-text").text("I'm holding…");
    $("#placesObjectsLabel .accordion-header-text").text("I can see…");
    $("#placesObjectsLabel,#placesObjectsAccordion").show();
    $(".cc-spiral").remove();
    updateList = realUpdateList;
    delete startCharGen;
    delete endCharGen;
  };
})();

Next challenge will be the verbs list :-p


(in pseudocode, it may be clearer to understand what I'm doing.

Existing updateList:

  • Get the name of the currently selected item
  • Empty the pane
  • Loop over the items in listData
    • Create a new <li/> for each
    • If its name matches the selected one…
      • …make it selected
  • If we didn't select one
    • Hide the verbsList

My version (excluding all the stuff to call the default version for the inventory, etc):

  • Set a toremove attribute on all <div/>s that have the appropriate class
  • Loop over the items in listData
    • If a <div/> exists for each
      • Remove its "toremove" attribute
    • else
      • Create that <div/>
  • Delete everything that still has a "toremove" attribute

I figure that this way could be useful in some cases, because if you're doing any kind of javascripty thing (or even just have an animated GIF as part of the listalias), it doesn't delete and then recreate items that are still visible.
Heck, you could even 'animate' it so that objects removed from 'Places and Objects' and added to 'Inventory' fly from one list to the other :p That's a bit of silliness that would take more effort than it's worth for me, though.


OK :D This is pretty much as I want it.

I know it's not a common thing, but maybe someone will appreciate it :p Try putting this in a game, then calling JS.startCharGen() and JS.endCharGen(). Kind of trippy? I think it works for me because it fits the theme of my game.

(Note - using my version of the JS-in-web-editor script. So searchreplace « to < and » to > to make this work in a standard JS file)

(function() {
  var realUpdateList = updateList;
  startCharGen = function () {
    $("#inventoryLabel .accordion-header-text").text("Character Creation");
    $("#placesObjectsLabel,#placesObjectsAccordion").hide();

    updateList = function (listName, listData) {
      if (listName == "inventory") {
        realUpdateList(listName, listData);
      } else {
        $(".cc-spiral").attr("toremove", "true");
        $.each(listData, function (key, value) {
          var data = JSON.parse(value);
          var objectid = "cc_object_" + data["ElementId"].replace(/\W/g, "");
          var item = $("#"+objectid);
          if (item.length » 0) {
            item.removeAttr("toremove").data(data).html(data["Text"]);
          } else {
            item = $("«div/»", {class: "cc-spiral", id: objectid}).data(data).html(data["Text"]).appendTo("#gameBorder");
            startSpiral(item);
          }
        });
        $(".cc-spiral[toremove]").attr("toremove", "confirmed");
      }
    };

  };

  endCharGen = function () {
    $("#inventoryLabel .accordion-header-text").text("I'm holding…");
    $("#placesObjectsLabel .accordion-header-text").text("I can see…");
    $("#placesObjectsLabel,#placesObjectsAccordion").show();
    $(".cc-spiral").hide();
    updateList = realUpdateList;
    delete startCharGen;
    delete endCharGen;
  };

  var startpos = $("#inventoryAccordion").offset();
  function startSpiral(element) {
    element.css({position:"fixed", left: startpos["left"], top: startpos["top"]});
    var outer = $("«div/»", {id: element.attr("id")+"_outer"}).appendTo(element.parent());
    outer.css({position:"fixed", left: startpos["left"]+element.width()/2, top: startpos["top"]+element.height(), marginTop: 0, marginBottom: Math.random() * 720});
    var angle = Math.random() * 360;
    startpos["top"] += element.height();

    function respiral() {
      var top_limit = element.height() / 2;
      var left_limit = element.width() / 2;
      var bottom_limit = window.innerHeight - top_limit;
      var right_limit = window.innerWidth - left_limit;

      var width_avail = right_limit - left_limit;
      var height_avail = bottom_limit - top_limit;
      // using marginTop as radius, and marginBottom as delta-angle (in degrees)
      angle = (angle + parseInt(outer.css("marginBottom"))) % 360;
      var mb = parseInt(outer.css("marginBottom"));
      var targets = {
        top: top_limit + (0.5 + Math.random()) * (bottom_limit - top_limit) / 2,
        left: left_limit + (0.5 + Math.random()) * (right_limit - left_limit) / 2,
        marginBottom: ((mb«360)? 0 : 360) + Math.random() * 360
      };
      outer.css("marginBottom", 360);
      targets["marginTop"] = Math.min(
        right_limit - targets["left"],
        targets["left"] - left_limit,
        targets["top"] - top_limit,
        bottom_limit - targets["top"]
      );

      outer.animate(targets, {
        specialEasing: {top: "swing", left: "swing", marginTop: "swing", marginBottom: "linear"},
        duration: 2000 + Math.random() * 3000,
        progress: function (promise, i) {
          var radius = parseInt(outer.css("marginTop"));
          var delta = parseInt(outer.css("marginBottom"));
          if (element.attr("toremove") == "confirmed") {
            outer.stop();
            outer.remove();
            element.remove();
          } else {
            var setting = {
              top: parseInt(outer.css("top")) + radius*Math.sin((angle+delta) * Math.PI/180) - element.height()/2,
              left: parseInt(outer.css("left")) + radius*Math.cos((angle+delta) * Math.PI/180) - element.width()/2
            };
            element.css(setting);
          }
        },
        complete: function() {
          if (element.attr("toremove") == "confirmed") {
console.log("Stopping "+outer.attr("id")+" weirdly!\n");
            outer.remove();
            element.remove();
          } else {
            respiral();
          }
        }
      });
    }
    respiral();
  }
})();

(Also, if you haven't played with a language that does closures before, see if you can understand what I'm doing here. And I know that this has a horrible memory leak; I need to fix that still)

EDIT: No it doesn't. I think everything's in scope where it should be.


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums