Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

1 decade ago by Dropkick

How exactly can I save a level state so that any entities killed, power-ups collected, etc stay the same when the player returns to the level?

1 decade ago by Joncom

By doing it manually.

In main.js add the following code:
// important that you keep this accurate between levels
// can be a number or string
current_level: '', 

killed_entities: {},

Then your entities should have:
kill: function() {
    // Create an object for the current level if it does not exist yet.
    if(typeof ig.game.killed_entities[ ig.game.current_level ] === 'undefined') {
        ig.game.killed_entities[ ig.game.current_level ] = {};
    }
    // Store the ID of the current entity.
    ig.game.killed_entities[ ig.game.current_level ][ this.id ] = true;
    // Kill the entity.
    this.parent();
}

And then back in main.js you want to customize your loadLevel method.
loadLevel: function(data) {
    // Load the level, as usual.
    this.parent(data);

    // Quickly kill all the entities that are supposed to be dead.

    // Is there "persistently dead" data to check against?
    if(typeof this.killed_entities[ this.current_level ] !== 'undefined') {
        // Check all entities...
        for(var i=0; i<this.entities.length; i++) {
            // Against "persistently dead" data.
            for(var id in this.killed_entities[ this.current_level ]) {
                // Is this entity supposed to be "persistently dead"?
                if(this.entities[ i ].id === id) {
                    // Kill the entity.
                    this.entities[ i ].kill();
                }
            }
        }
    }
}

An alternative option that might be simpler but would depend on each entity having some unique identifier, would be to loop through the level data itself and remove the entity. For example, loop through LevelExample.data.entities and splice out the ones that should stay dead before you call loadLevel.

1 decade ago by spacehunter

Another option would be to use localstorage for persistent storage. Imagine if the user closed their browser then came back to your game on a new instance of the browser, you could detect the current state of the game and set it up properly.

There's even an Impact plugin you could use!

1 decade ago by Dropkick

Thank you for the replies! Im trying to implement it your way, Joncom, I figured I'd have to make some sort of function like that, I just couldnt rap my head around the logic needed.

I might look into local storage later, Spacehunter. Thanks for the links!

1 decade ago by Dropkick

Quote from Joncom
By doing it manually.


I've implemented it exactly as you said, but its still spawning the killed entities. Have you done it with this method before? I mean the logic all makes sense, but in the documentation it says that the entity ID might change with every level load. So I dont know if that's the problem or not.

EDIT: Yeah, I'm pretty sure this is the problem, I sent the ID to the console on every death of the respawn and it's ID went from 2, 32, 52... So I dont know if there is a way around this or not?

1 decade ago by drhayes

You've got the opposite problem, too: the player may have taken something out of the level and then died before checkpointing, so now that thing has to go back.

I'm starting to see why Metroid only tracked specific objects like power-ups and not every single enemy. ( =

I'm working on a blog post on how I'm handling it for my RPG-ish game but I've been hesitating because my solution feels a little overblown. Here's a summary:

I have a PlayerInfo class that gets instantiated in main.js once. It maintains two lists: a list of game states that have been checkpointed, and a list of game states that haven't been checkpointed yet. When the player runs over a checkpoint, I concat the latter list onto the former. If the player dies before checkpointing, I iterate over the "current" game states and unapply them.

GameState looks like this:

ig.module(
  'game.system.gameState'
)
.requires(
  'impact.impact'
)
.defines(function() {

  // As the player moves around in a level, we need to track
  // what they have done. If the player dies before checkpointing,
  // either by touching a checkpoint or by entering a level portal,
  // then we need to undo everything that the player has affected
  // on the level, and any effects those things might have had on
  // the player.
  GameState = ig.Class.extend({

    init: function() {},

    // Called when the gamestate should be applied. If this
    // is the state of an entity, that entity should be removed
    // from the world.
    apply: function() {
      // By default, remove the entity from the level.
      ig.game.removeEntity(this.entityInstance);
    },

    // Called to give this frame a chance to modify the
    // player behaviors in whatever way.
    modifyPlayer: function(player) {},

    // Called to give this frame a chance to undo the
    // player behavior changes it made earlier.
    unmodifyPlayer: function(player) {},

    // Called when the object is removed from player,
    // whether dropped or because of player death.
    unapply: function() {
      // By default, spawn another one in the level.
      var x = this.entityInstance.pos.x;
      var y = this.entityInstance.pos.y;
      ig.game.spawnEntity(this.entityType, x, y);
    }
  });
});

Suppose I have an item that gives a player a new ability. It will override modifyPlayer to make any changes to how the player works (player can now fly, etc). The default implementations of apply and unapply take care of adding and removing the entity from the level. There's an override of GameState for entities that have to be added in/removed if the player hasn't checkpointed yet.

If the player gains an ability like flying before checkpointing and then dies, unmodifyPlayer handles removing the new behaviors and unapply handles resetting the entity.

Like I said, maybe this is overblown.

1 decade ago by giodif

I don't know how you are generating your enemy entities, but I've found that by naming them in weltmeister, I can track them by name instead of id ( like you said, ids are problematic because they change... derp ).

say I have three rat entities ( enemies, of course ), I'd name them 'rat1', 'rat2', 'rat3'. If I have wolf entities they'd be 'wolf1', 'wolf2', 'wolf3'... etc.

That's just the naming convention I use. Really, they could be named anything.

It's a little more work, but I've got dozens of levels and it's never been a problem. Saving this data is also handy if your character moves back and forth between areas over and over again ( Which is how my game works ).

I also extended the game class to add a getEntityByGroup function for entities that are grouped together. For instance, I have a barrier entity that is actually a collection of small collidable blocks. I use this entity to create destroyable parts of the level. When a barrier is destroyed, I save the group name and use that to filter out entities when a level loads.

1 decade ago by Joncom

What giodif said should work. Instead of storing id which evidently changes, set a unique name value for each entity in Weltmeister. Then change up the one line from:

// Store the ID of the current entity.
ig.game.killed_entities[ ig.game.current_level ][ this.id ] = true;

To:

// Store the name of the current entity.
ig.game.killed_entities[ ig.game.current_level ][ this.name ] = true;
Page 1 of 1
« first « previous next › last »