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 ape

I know slope collision works with sloped collision tiles within collision maps (or at least it has in recent versions).

I'm curious if anyone is using the same collision routines with entities.

I need to be able to dynamically insert slopes ahead of a player on a infinitely scrolling repeated background and I'm thinking that entities are going to help a lot with performance.

I was able to dynamically insert collision map "columns" ahead of the player (similar to how the Drop example game adds rows), removing them once they were off screen, but the performance hit was pretty big. Lot's of choppiness as the new columns were added (I tried adding single columns, columns in batches ranging from 2 to 200 - no getting rid of the choppiness).

A while back I ported a version of Box2D that was more up to date with the latest Box2D API to Impact as a plugin (I'll post a link to the github repo in another post) but that currently only supports entity collision with collision maps as well. It also breaks within Impact 1.20, so I'll need to work on that. Creating entity to entity collision is trickier since entity shapes are likely to be much more dynamic (for example, my test entity is a car with wheels - a lot more different then a bouncing ball).

I'll dig into the slope related code to see what I can find - hopefully I'm not the first to want to do this.

1 decade ago by Arantor

Entity collision is actually slower than collision map based collision.

If you're having trouble with performance of the collision map, that suggests to me there are other issues to be dealt with.

1 decade ago by SlouchCouch

depending on how fast your collision map is scrolling, i had issues with entities and slope behavior and entities getting caught on slope tile boundaries (among other annoying things) which usually showed around 100 pixels per second scrolling, if i can remember correctly.

1 decade ago by ape

@arantor:

How are you measuring the difference in performance between slope and entity collision?

I'd be surprised to find that when considering just the collision performance of an Entity vs. a CollisionMap tile, the two were anything but identical, give or take a millisecond.

I've since revisited dynamic CollisionMap creation. I was able to speed it up a bit by only shifting/pushing changes to "rows" where I wanted changes to occur, rather than removing entire columns from the left and adding new columns to the right.

That said, vertical collisions don't seem to work with newly added tiles. Horizontal collisions do work.

For example, all of the tiles below were added to ig.game.collisionMap dynamically. The bike doesn't fall through the tiles, indicating that horizontal collisions are working, but the bike will drive right through the wall in front of it.

/><br />
<br />
Changing the tile to a slope doesn't change anything. The bike will drive right through it.<br />
<br />
So, I'm stumped.<br />
<br />
I'll probably reintroduce my Box2D plugin with this approach and see if that changes anything, but for this game it's way overkill. Would much rather than simpler solution work.			</div>
		</div>
			<div class=

1 decade ago by Arantor

Oh, they are different, because of how they're implemented. When checking collision against collision maps, it's a simple look up against what's in the map for the tile(s) the entity is on.

When checking collision against entities, a hashmap is built of all the active entities, to figure out what ones are in the vicinity of each other, and after having done that, it goes through and compares them specifically to be sure.

Even the manual makes mention of this fact.

Now, two entities colliding vs one against the map might be pretty fast, but I guarantee you that collision against the map is faster.

How exactly are you adding to ig.game.collisionMap?

1 decade ago by ape

@arantor

Depending on how you look at it, you're correct. To be clear, starting with entity.js, this is what happens within an entity's update:

var res = ig.game.collisionMap.trace( 
  this.pos.x, this.pos.y, mx, my, this.size.x, this.size.y
);
this.handleMovementTrace( res );

For each entity update, ig.game.collisionMap.trace returns a res object after doing the "simple lookup" you describe while handleMovementTrace actually adjusts velocities and such depending on the properties of the res object.

An entity's update happens when the Game object's updateEntities is called within the Game object's update method.

After that, within the Game's checkEntities method, we sort out Entity collisions.

Isolating collisionMap tile collisions from Entity collisions is indeed simpler. But normally, both happen on every game update.

To answer your question, I'm doing essentially this in my Game's update:

// grab a snapshot of the collisionMap data
var tmpData = ig.copy(ig.game.collisionMap.data);

// ensure that "row" 9 is always solid
tmpData[9].shift();
tmpData[9].push(1);

// randomly drop a "wall" in on row "8"
if (Math.floor(Math.random() * 2) != 0) {
  tmpData[width-1] = 2;
}

ig.game.collisionMap.data = tmpData;

// update the background map to reflect changes made to the collisionMap
ig.game.groundMap.data = ig.game.collisionMap.data;

I've also tried, without success, a similar approach that swaps out the entire collision map:

// grab a snapshot of the entire collisionMap
var tmpCm = ig.copy(ig.game.collisionMap);

// do stuff to its data

// use it as the new collisionMap
ig.game.collisionMap = tmpCm;

My next approach is going to be run the debugger when loading a collisionMap compared to modifying a collisionMap so I can see where the two differ. That's going to be somewhat tedious, but at this point I'm not sure there's much else I can do.

EDIT: fixed code formatting issues.

1 decade ago by Arantor

What's width, exactly? tmpData[width-1] is being updated but it's never clear what width is, are you sure that width is the same as tmpData.length?

1 decade ago by ape

@arantor

Sorry - I mangled the code snippet as I pasted it here.

It should read more like this:

var width = Math.floor(ig.system.width / this.tileSize);

// grab a snapshot of the collisionMap data
var tmpData = ig.copy(ig.game.collisionMap.data);

// ensure that "row" 9 is always solid
tmpData[9].shift();
tmpData[9].push(1);

// randomly drop a "wall" in on row "8"
if (Math.floor(Math.random() * 2) != 0) {
  tmpData[8][width-1] = 2;
}

ig.game.collisionMap.data = tmpData;

// update the background map to reflect changes made to the collisionMap
ig.game.groundMap.data = ig.game.collisionMap.data;

Also, I began to wonder, after explaining how collisions worked, if what I said was actually accurate.

On second pass, it's sort of right.

While its actually a bit tangential to this thread, it might but useful for those who might have been confused by what I'd said earlier if I tried to describe how collisions work. If anything I say isn't right, please do mention it - it's not the easiest thing to follow through the code.

Game#update calls the Game#updateEntities function. Game#updateEntities calls Entity#update on each entity. Entity#update calls ig.game.collisionMap.trace, passing in that entity's position, velocity, and size.

This is where it gets tricky.

ig.game.collisionMap.trace creates a res template, then populates that res template's properties using CollisionMap#_traceStep.

CollisionMap#_traceStep checks to see if the entity has horizontal velocity. If it has horizontal velocity it tries to determine if there's a type of tile it can do something with at the collision map tile sharing the same space as the entity. If there is, it sets the res object's properties accordingly.

It essentially does the same thing for vertical velocity.

During the trace it'll call CollisionMap#_checkTileDef. If CollisionMap#_checkTileDef determines the tile it finds is a slope, it changes the res.slope property from false to an object containing values that describe the "line" of the slope.

If it's not a slope, CollisionMap#_traceStep does other stuff not exactly relevant to slopes.

Then we're back to Entity#update. Now, keep in mind that so far we've not even done anything with Entity to Entity collisions.

Entity#update kicks off Entity#handleMovementTrace, passing in the results of the collision trace.

Entity#handleMovementTrace sets the entity's horizontal and vertical velocity based on what it finds in the passed in res object (which was populated in CollisionMap#trace).

Then it sets the horizontal and vertical velocity depending on the res.slope properties (if there are any) as well as the angle of the entity. Finally, it sets the entity's position to be the same as that found in the res object. Initially, during the CollisionMap#trace, res.pos is set to that of the entity it's checking collisions for. During the course of tracing, the res position can change, which is why it's eventually used in Entity#handleMovementTrace to set the entity's position.

Again, we've not yet dealt with Entity to Entity collision.

Once every entity in the game has been updated (each following the path I just described) Game#update calls Game#checkEntities.

Game#checkEntities then solves collisions for each Entity in the game. Entity collision is solved by calling Entity#checkPair, passing in entities that haven't been checked for collision yet, but have positions that overlap.

It's at this point I'll skip over some details for a bit because they definately get complicated. Entity#checkPair determines what kind of collision to apply, then solves that collision using Entity#solveCollision.

This is where it gets interesting. Regardless of the axis or type of collision, Entity#solveCollision ultimately uses CollisionMap#trace to work out the resolution to the collision, using that resolution to set properties (like velocity and position) on the affected pairs of entities.

So, to be accurate, slopes based on collisionMap tiles is simpler than slopes based on entities. ;)

1 decade ago by Arantor

OK, so again, how are you sure that width is right?

Sounds to me as though you need to push an item onto the list, rather than doing it that way.

That level of depth is great for understanding how collisions work in detail, but I think the problem you're having is that the collision map is being updated incorrectly rather than anything else. (And I stand by my original statement that an entity vs collision map will be faster than entity vs entity collisions, heh)

1 decade ago by ape

I figured out what my original problem was and I have to say - it takes a lot to come back here and admit it.

You know that thing about Occum's Razor?

Well, I give you exhibit A (aka, my original code):

update: function() {
this.parent();
/*
  do all sorts of stuff here
*/
}

And exhibit B (aka, the right way, at least in this case):

update: function() {
/*
  do all sorts of stuff here
*/
this.parent();
}

I knew that if you're going to do anything to the "physics" of an Entity, you do so before you call this.parent(). I just blindly pushed on, seeing it in the wrong place, not even thinking about it.

Ugh.

The silver lining is that I wrote and deleted a lot of amazing code in an effort to figure this out. All of which is safely stashed away in a git repo. I'll have to drag some of it back out and see if it would have worked after all.

1 decade ago by Arantor

Ouch! Having been bitten by such things in the past, I can fully understand the head-meeting-desk moment that would have ensued!

I'm just glad you figured it out :)
Page 1 of 1
« first « previous next › last »