I discovered a lot of new info since I posted this question so I have completely rewritten it:
I have run into some problems while implementing gravity and jumping in my tile-based game.
Sometimes when my character lands between tiles after a jump, the characters falls through them.
The problem certainly is not that my speed is too high since my max speed is the same as my tile-size. Also, the problem does not occur after every time the character jumps. I can often make a jump, get to max velocity, and still land well. But sometimes the character just falls through.
My level exists of layers of tiles. Each layer has it's own collision-type. So every tile in the same layer, follows the same rules for collision.
In my current set-up all layers use per-pixel collision.
This is how I update the player coordinates
http://pastebin.com/qVc6gv6T
This is the class where I calculate my collissions.
http://pastebin.com/7GqrFih6
In the update I just do:
controls.Update(player);
physicsEngine.HandleCollissions(levelManager, player);
I imagine that the problem could be because the player gets moved to another tile after collission. Collides with the other tile. But that doesn't count since the other tile already has been checked for collision?
Or could it be because I use foreach instead of for-loops?
You say the error occurs after jumping. So, your character falls toward a tile (has some positive velocity.Y) and hits it. The collision code executes the // the player comes FROM ABOVE and collides with the tile block. You run a loop that sets player velocity to zero and moves the player out of collision. This loops calls a function using a term tile as an argument. I assume you loop through a set of tiles in order to collide with more than a single square. Am I right?
If I am, then the problem occurs after that first collision and correction. Now your player has a velocity.Y of 0, but they are colliding with a new tile. So in spite of your comment about the meaning of your else block, you may have more position changes happening:
if (player.Velocity.Y > 0)
else // if (moveVector.Y < 0) // what you commented
else // if (moveVector.Y <= 0) // what your else really means
Now sometimes (only when you have slightly mis-alligned per-pixel collisions) you have course corrections happening the the wrong direction. That would produce a fall-through effect. You could try setting a break point in the // the player comes FROM UNDER and collides with the tile block, and then running the program in a scenario that shouldn't cause player.WorldPositionY += 1; to happen. If it happens when it wasn't supposed to, then you have your culprit.
I am doing a lot of speculation here. I think you should post more code so that we can know for sure. But perhaps a paste bin would be appropriate place for it.
Related
I am seeming to have difficulty keeping my sprite nodes inside a map boundary that I have set up in the following way:
I have an SKNode *enemy that moves around an SKScene by goals and behaviors courtesy of GameplayKit from iOS 9. Currently the node wanders, and avoids obstacles that are defined GKPolygonObstacle objects. I have my bitmask set up so that any obstacle is deemd category wall, which the node is told to collide with (AKA disallow passing through).
In my didBeginContact:(SKPhysicsContact *)contact I am handling these collisions. All is working exactly as planned and there are no issues when manually moving this enemy.
However, the problem begins when I have the enemy wander around the scene through an SKGoal *wanderGoal set up as
// Low --> 0.5 Lowest --> 0.25
enemy.wanderGoal = [GKGoal goalToWander:low];
[enemy.agent.behavior setWeight:lowest forGoal:enemy.wanderGoal];
// Add obstacles to avoid for each of the inner map nodes
// that act as impassible areas for the enemy to pass through.
NSArray *obstacles = [SKNode obstaclesFromNodePhysicsBodies:innerMapArray];
/** This goal does not change --> enemies will ALWAYS
avoid the obstacles in the level map. This should always
be set to the highest priority of the enemy goals
*/
enemy.avoidGoal = [GKGoal goalToAvoidObstacles:obstacles maxPredictionTime:10];
// Highest --> 250
[enemy.agent.behavior setWeight:highest forGoal:enemy.avoidGoal];
The enemy moves randomly as expected, and seems to avoid the obstacles most of the time...yet on the occasion the enemy does in fact pass through the map barrier. Let me expand on this:
The map barrier is essentially a rectangle, and I have set up 2 nodes that act as a shell that represent the left half and the right half of this shape. These nodes have a thickness of 100 points so they are not simply CGPath refs but rather shapes. They act as these two brackets act: [] (my halves are flush touching at the middle).
My question is such:
How can I prevent the enemy from passing through these obstacles with using either physics with the bitmask categories, or by the goal behavior? (Or both together)
I understand that while a GKGoal is a suggested behavior it does not guarantee this goal to be reached (but it can be ~95% sure it wont happen as Apple's AgentsCatalog shows). But, what I don't understand is why the enemy does not simply "slide" along the edge of the boundary as the goal tells it to (try to) "pass" through such boundary.
This "sliding" behavior does happen when I manually move the enemy around the scene, and as I attempt to move it passed a boundary deemed an obstacle, it slides towards the direction that I am having it move (just as any video game does that has map boundaries).
SO
If someone can help me prevent this from happening / explain how to approach preventing the enemy from ever passing through these (supposedly) "impassible" areas, I would be most appreciative.
FYI: If you are unclear with what I am describing / how I have created any objects, please ask and I will provide more info to help.
I'm doing a game like tetris. There are objects which are falling from the top to the bottom of the screen. When the pile of object reach the line, the game is over.
I tried to set a boolean to detect when the object pass 2 time in the line the game ends, but it don't work like that so I don't really know how to do this.
Maybe we can detect if the object stands on the line more than 2 seconds ?
Thanks
EDIT:
To simplify the problem I put the line of the top of the screen (self.frame.height), and I spawn the objects under this line, so they never cross the line before the game is over.
The problem now is I have to spawn the objects 40 pixels below the line, or a collision is detected at the spawn point. (It does nothing if I set usesPreciseCollisionDetection = true).
So the 40 pixels collision detection are normal ?
Why would the item pass the line 2 times? Items always move down. So really, once an item is past the line, you know it will never go above (Well, OK, that's not true -- since you can rotate an item, you could get a long one horizontal and then rotate it to vertical ... do Tetris items come out horizontally?).
So really, your test would be more "does it never fully cross the line". E.g. if you know that an item moves at speed X, you could probably just calculate the time it should take to move from top to past the line, then wait that long, then see if it still intersects the top area above the line. If it does, the game is lost.
Alternately, you could set a flag when an item comes to rest on another item. If that flag is set, and the item still intersects the area above the line, the game is lost.
PS - Keep in mind that Tetris is a brand name. Be sure to name your game something else. :-)
I'm making a platformer using Actionscript 2. I got the jumping and gravity and everything going, but I'm limited to one "ground". As one might imagine, platformers require multiple "grounds" for jumping onto and falling off of. I tried editing the "ground" movie clip so that it was several blocks with nothing between them, but when I try this, my character will jump, land at the peak of its jump, and repeat the process until it lands on the top of the ground movie clip, then behave regularly, jumping and landing on top of the ground movieclip, even if there's no part of the ground movieclip to land on.
Here's my ground-gravity code.
if(this.hitTest(_root.ground))
{
this._y -= gravity;
gravity = 0;
jumping = false;
}
When you use hitTest between two MovieClips, it doesn't matter if there's nothing inside the movieclip, as long as the hittesting movieclip is INSIDE the bounding box (the blue outer rectangle of a movieclip when you select it) of the other movieclip.
To solve your problem, but still have many grounds in the same MovieClip, you have to use the second usage of hitTest, hitTest(x, y, shapeFlag) -- this will not check if two movieclips are hittesting each other, but rather if a MovieClip is touching a POINT (just an x and a y coordinate). But the real advantage of using this is the third parameter, shapeFlag, which is a Boolean value (either true or false) -- if it's false, then the hitTest will take the whole movieclip into account, meaning that even if there are empty spaces, those will be included in the hitTest, WHILE, if it's true, then only the actual shape of the MovieClip will be considered during the hitTest.
First of all, you have to get inside your Character's MovieClip and move him so that the registration point of the movieclip (you know that small plus sign), is at the BOTTOM of your character. Then, change your code to this:
if(_root.ground.hitTest(this._x, this._y, true))
{
this._y -= gravity;
gravity = 0;
jumping = false;
}
This will check if the SHAPE of the ground MovieClip (meaning only the platforms, NOT the empty spaces between them) are touching the registration point of your MovieClip, which is located at the bottom, at the feet, of your character. So, whenever the feet of your character are touching any of the platforms inside the ground movieclip, the code will be executed and your character wil stop.
Hope this helps :)
i'm creating simple iOS game with Cocos2D and Box2D. In my game user has to create full word by shooting to squares with letters. If shooted letter is correct the square should explode, otherwise the square should fall down. I have created simple contact listener and I can detect collision between bullet and square but the problem is how to avoid collision force when letter is incorrect? I that situation (incorrect letter) i want square to simply fall down without applying collision force to the square.
Maybe I can delete the square and create new one at the position of deleted, but i think it's not the best idea :)
One suggestion I would make would be on collision, if the letter is incorrect, set the bodies x and z velocities to 0. This way when they collide with incorrect squares they will simply fall.
Another thing you could do would be to set the target square's body as fixed ( or rigid, I can't remember what it's called in Box2d off the top of my head). So even if an incorrect letter collides with it, it will not budge but the letter will bounce off it. And it the letter is correct, you can explode it as normal.
The solution I would advice is to set the velocity of the bullet to 0 in both directions in the PreSolve callback of the contact listener. Obviously you do a check in the PreSolve function. This way as the function is called PreSolve, the collision calculation have not happened yet. so setting velocity to 0 will make the bullet to have no effect on the square in terms of force.
I'm trying to move a sprite around a CCTMXMap in a smooth fashion. I've figured out how (using CCActions) to move from tile to tile, but I get gaps in my animation (it pauses for a frame while it reevaluates which direction to walk). I've tried moving the character in a scheduled update: method, but that gets messy when you try and restrict the sprite to only moving from tile to tile. Any suggestions on how to get the clean, consistent animation without messy manual animation using update?
Yes, don't use actions. You'll always have the 1-frame delay problem when using CCActions.
Moving the sprite in update is really pretty simple. Especially if you restrict movement to a speed (points per frame) that is clearly divisible by the tile size. For example if your tiles are 40x30, then horizontal speeds of 1,2,4,8,10 would work fine. Vertically 1,2,3,5,6,10 would work.
Update the position by this number, cast it down to int, compare it with the destination location:
if ((int)currentPos.x == (int)targetPos.x && (int)currentPos.y == (int)targetPos.y)
{
NSLog(#"I'm there!");
}
The reason for casting to int is to avoid rounding errors in floating point values.
Another solution would be - especially if your character can only move in one direction at a time - to figure out the number of frames it will take him to get there. If the character has to move 40 points to the right, and he moves at 4 points per frame, it'll take him 10 frames. Then just count the number of frames (how many times the update method ran) and if it reaches 10 (or 0 if you count down) then you know that the character has arrived without needing to check his position.