I'm working on a Java Bomberman clone, using a grid system, and I'm not really satisfied with the movement right now. When the player presses a movement key, the character starts to move (with 0.25 speed). The player loses the control, and the character keeps moving until it has moved a full tile. The player only regains control when the character gets to the center of the next tile.
This makes it's too "laggy". If I want to change direction now, I can't.
Maybe I could make the base of the character smaller than the size of the sprite, meaning I would have to check ahead of the corners to check if it was a valid move. Any thoughts?
Thanks!
I just played Bomberman a few minutes ago :)
You can move pretty smooth, there no grid calculations.
I haven't used Java that much. I use Flash a lot. Is the Grid for checking collisions ?
What is it for exactly ?
Would it make sense to have something like(I'll try to sketch it):
float vx,vy = 0;//velocity on x and y
Character bomberman
void keyDownHandler(KeyboardEventSomething event){
if(key is Left && ! Right ) vx -= .5;
else if(key is Right && !Left ) vx += .5;
//idem for Y axis
}
void keyUpHandler(KeyboardEventSomething event){
vx = vy = 0;
}
void updateLoop(){
bomberman.x += vx;
bomberman.y += vy;
}
I might be a bit off, because I'm not sure how much you want to clone Bomberman or not. What you're describing with the grid movement seems closer to hopmon
Don't disable user input. Ever. Constantly poll for it.
Have a Tick() or OnFrameEnter() function that does the following:
Poll the keyboard/joystick/whatever, and cache the last direction entered by the user.
Check the position of the character.
If the character is idle in the center of a grid square, set it's velocity in the proper direction and upate the movement one step, unless there's a wall/collision object in the way. Also clear out the last key press to some invalid value.
Else if the character is already moving, update the position of the character, checking for collision with a wall, or proximity to a direction changing node (intersection). If it collides with a wall, stop the character. If it's close to a direction changing node and can travel in the cached direction, change the direction and clear the cached direction. Else if the input direction is opposite the current direction (it's in a hallway and the player wants to reverse), reverse the direction and then clear the key press. This all assumes that the character should continue moving, always, until it hits a wall and stops. If you want the character to stop anywhere, a reverse direction key should simply stop it in place.
Caching the key press allows the player to preemptively change directions as the character approaches an intersection. This way the character doesn't have to wait to stop before moving on, and the player doesn't feel the game is unresponsive. Polling constantly lets the player reverse directions at any time, and makes direction changes at intersections seem faster.
You should be able to get rid of current sprite and load the new one exactly when you need it - i.e. if the character moved half way to the next tile and the player presses a key to return, cancel the sprite and load the new one starting at 0.5.
I guess it depends on how you want it to behave.
Say you are moving up, and you click right.. do you want it to stop moving up and go right?
I would store the previous grid location when you make a movement. that way if you click to move elsewhere you can hop backwards and change the movement direction..
Or if you are moving up and you click down... you could set the movement speed to be the opposite of what it is...
It is hard to answer with out knowing what you want it to behave like.
It sounds like you update the players position (start of the animation) by changing the grid cell in which its contained.
To be able to achieve the desired effect, the sprites render position should be independent of where the entity represented by that sprite is located on the grid. And allow the user to move inside that grid within a range of the cell's center without changing cells. If this range is not chosen correctly you may en up with the "doh! im in this (visually) cell but it says im in the future cell" problem, or the "my avatar is overlapping a wall".
Dont change the players cell until he is within a range (lets say 1/3 of the bounding sphere of the sprite) from the limits/borders of the cell that contains him. You would also have to modify the animation process for it to be interruptible.
This is independent of the degrees of liberty you give the player (like, it could only move up, down, left, right, and diagonals vs 360 degrees)
Another thing you should watch out for is, if the sprite is larger than the cell size. For instance, a Fat monster, or a Snake boss which spans across X cells but not necessarily in rectangular form.
Related
In Java, I'm writing a mobile app for Android to interact with some dynamic balls with some classes I wrote myself. Gravity is determined on the tilt of the phone.
I noticed when I have a bunch of balls bunched up in a corner that some of them will begin to jitter, or sometimes slide while colliding with other balls. Could this be because I'm executing steps in the wrong order?
Right now I have a single loop going through each ball to:
Sim an iteration
Check collisions with other balls
Check collisions against scene bounds
I should add that I have friction with the bounds and when a ball to ball collision occurs, just to lose energy.
Here's a portion of code of how collision is being handled:
// Sim an iteration
for (Ball ball : balls) {
ball.gravity.set(gravity.x, gravity.y);
if (ball.active) {
ball.sim();
// Collide against other balls
for (Ball otherBall : balls) {
if (ball != otherBall) {
double dist = ball.pos.distance(otherBall.pos);
boolean isColliding = dist < ball.radius + otherBall.radius;
if (isColliding) {
// Offset so they aren't touching anymore
MVector dif = otherBall.pos.copy();
dif.sub(ball.pos);
dif.normalize();
double difValue = dist - (ball.radius + otherBall.radius);
dif.mult(difValue);
ball.pos.add(dif);
// Change this velocity
double mag = ball.vel.mag();
MVector newVel = ball.pos.copy();
newVel.sub(otherBall.pos);
newVel.normalize();
newVel.mult(mag * 0.9);
ball.vel = newVel;
// Change other velocity
double otherMag = otherBall.vel.mag();
MVector newOtherVel = otherBall.pos.copy();
newOtherVel.sub(ball.pos);
newOtherVel.normalize();
newOtherVel.mult(otherMag * 0.9);
otherBall.vel = newOtherVel;
}
}
}
}
}
If this is the only code that checks for interactions between balls, then the problem seems pretty clear. There is no way for a ball to rest atop another ball, in equilibrium.
Let's say that you have one ball directly on top of another. When you compute the acceleration of the top ball due to gravity, you should also be doing a collision check like the one you posted, except this time checking for dist <= ball.radius + otherBall.radius. If this is the case, then you should assume a normal force between the balls equal to that of gravity, and negate the component of gravity in line with the vector connecting the two balls' centers. If you fail to do this, then the top ball will accelerate into the bottom one, triggering the collision code you posted, and you'll get the jitters.
Similar logic must be used when a ball is in contact with a scene bound.
Since I've been experimenting with my own Phys2D engine (just for fun), I know you're talking about. (Just in case - you may check my demo here: http://gwt-dynamic-host.appspot.com/ - select "Circle Collisions Demo" there, and corresponding code here: https://github.com/domax/gwt-dynamic-plugins/tree/master/gwt-dynamic-main/gwt-dynamic-module-bar).
The problem is in a nature of iterations and infinite loop of colliding consequences. When e.g. ball is reached the scene corner, it experiences at least 3 vectors of force: impulse of bounce from the wall, impulse of bounce from the floor and impulse of gravity - after you summarize all 3 impulses, reduce it according loosing energy algorithm, you have to have the new vector where your ball should be. But, e.g. this impulse directs it into wall - then you have to recompute the set of vectors again according to all the stuff: energy of bounce, impulses, gravity, etc. Even in case if all these impulses are small, you never get all of them 0, because of precision of doubles and your tolerance comparison constants - that because you have the "jitter" and "sliding" effects.
Actually, most of existing 2D engines have these effects one kind or another: you may see them here: http://brm.io/matter-js/demo/#wreckingBall or here: http://box2d-js.sourceforge.net/index2.html - they actually just make the small impulses to be absorbed faster and stop iterating when the whole system becomes more or less stable, but it is not always possible.
Anyway, I'd just recommend do not reinvent your own wheel unless it is just for your fun - or for your better understanding this stuff.
For last one (JFF) - here is good tutorial: http://gamedevelopment.tutsplus.com/tutorials/how-to-create-a-custom-2d-physics-engine-the-basics-and-impulse-resolution--gamedev-6331
For real things, I'd recommend to use the existing engines, e.g. Unity (https://unity3d.com/learn/tutorials/modules/beginner/2d/physics2d) or Box2d (http://box2d.org/)
Hope this helps.
Iterating through all the balls and changing the balls position for each iteration is probably the cause for the instability, you move a ball left to avoid collision on the right, and then you pushed the ball into another ball on the left, and then the left ball tries to push it back again.
From the top of my head I could recommend trying to sum up all the forces on each ball before doing anything about positioning. And if you iterate from the ball "on top" (furthest away from gravity source/direction) you can probably achieve a stable situation.
Basically, the top ball needs to first calculate forces between itself and the ball(s) under it, plus gravity, then the ball under will know how much force is coming from the top ball, and added with gravity it would also add to the force of which it is pushing the balls under it. When all balls know the forces they're pushed with you can transform that force into motion.
The way you are simulating the physics of the balls is bound to cause instabilities. Your collision resolution tries to separate the balls by projecting one of them in the opposite direction by the collision depth. This may fix the overlap for those two balls but chances are(especially when the balls are stacked) that the ball is now overlapping with another ball.
There are many ways to fix penetration. One of the simplest ways is to add a "bias" or a bit of a push to both bodies to force them to separate over the next couple of frames. This allows that energy to propagate and force all of the bodies apart. Problem is, the bias will often overestimate and cause a bit of a bounce. To fix that problem I'd recommend reading up on sequential impulse.
Making physics look realistic is not as easy as it may seem. Unless you don't mind instabilities I'd recommend spending some time reading up on different techniques or using an engine such as Box2D.
I am programming a 2D, grid-based Pacman game. All the tiles are 8x8 in size. In-game, the map tiles are treated as 16x16, and the characters (Pacman and the ghosts) are treated as 32x32. In actuality, they are all pulled from a spritesheet of 8x8 tiles. I store positions as the center point of each character. Since the character tiles are bigger than the map tiles, the map is built in a way that requires the characters being able to "overlap" onto blocked tiles.
To deal with this set of problems, I created an invisible Rectangle and attached it to the character's position. Where the position is an (x,y) point, the Rectangle is a box surrounding that point. This rectangle is essentially 16x16 in-game, and is in the center of the character, which allows for the overlap necessary.
This works fine if you're working with 8px as the global movement speed, but I'd like to treat 8px as "100% speed" and have complete control over character speed with a double that is in the range [0,1). The positions are stored as double points, so on that level, this is fine. I read the positions back as integers, though, since I'm working with pixels.
So the question I ask is essentially "if this moves X amount of pixels to direction Y now, will my collision box be touching a blocked tile? But if you're moving 5px at a time, this eventually causes a very obvious issue. Say you're at x = 0, moving right. The tiles are 16x16 in-game, as stated before, and you have two of these open before the third, which is blocked. So you move, x = 5, x = 10, x = 15, x = 20, we just got to the 2nd tile, x = 25, x = 30, x = 35 now we're in the 3rd tile... but wait. We can't go there, because X = 35 collides. And unfortunately, we needed to turn and start moving down, but we can't, because now our Y-axis isn't aligned properly with the grid. Our X position needs to be 32, but can't.
My question for everyone here is, what are my options? What are some ideas or insights you have? I have a feeling I'm making it more difficult than I need to.
sounds like you have...
Why not give your "pac-man" sprite a velocity vector? The vector will describe not only the speed at which "pac-man" is traveling but in what direction, meaning you can see ahead.
"pac-man" should be calculating and ultimately making a decision based upon the following conversation..."hey, moving at this speed and in this direction..in so many seconds I'm going to hit a wall, when does that happen?". The seconds don't even have to be seconds...they could be "squares".
You would need a function which takes in the initial movement vector (direction and speed) which returns a coordinate of an X,Y point where "pac-man" must stop, where he cannot go further and must change direction (the center of a tile adjacent to a wall). Each time "pac-man" changes direction, run this calculation again...you do not need to keep checking if the next square is passable. If his direction hasn't changed and his speed is constant..you only need calculate once and let the coordinate system do the rest.
With this approach, square size and velocity is irrelevant...until "pac-man" hits or within his next movement exceeds the stopping point, continue to move along the vector.
I have a mouse event handler and under mouseMoved I have this:
public void mouseMoved(MouseEvent e)
{
if((e.getX()>=0 && e.getX()<=100) && (e.getY()>=0 && e.getY()<=100))
{
robot.mouseMove(mainOutput.getX()+200,mainOutput.getY()+200);
}
}
What this does is that if the user tries to move towards the first 100x100 pixels of the frame, the pointer will translated. What I want to do however is recreate an "impassable wall".
Basically when the user attempts to go in the region it cannot pass the end points of the region. What I want to know is how would I go about doing this?
Unfortunately, this is a bit more difficult than it seems. Let me first illustrate the problems with a simple move-to-outside-of-boundary approach.
As you can see, in this case the boundary approach will detect the mouse inside the boundary, and move it to the blue point in the corner. Let me emphasize this, it detects the location of the mouse. What we want is to capture the movement of the cursor, and have it end at the red point. There are also other problems with this method that may not be immediately apparent.
So how do we capture the movement of the mouse? We need to capture the mouse displacement (black arrow) as a vector by keeping track of the previous location as well. I assume you can do this. So how do we calculate the new location? Well, we can perform line intersection of the displacement vector with the lines that make up the edges of the box. As you're only dealing with horizontal and vertical lines, it is greatly simplified and can be done with just a bit of thinking. If you're lazy, copy a generalized line intersection algorithm.
You may think that this approach is too rigorous, but it is the most robust way. I can already think of two additional issues with the simpler approach. Also, you're actually doing 2D hitbox detection. This is quite a useful thing to know.
Assuming the impassable area is a JPanel, you can add a mouse listener to it that will respond whenever the mouse enters the area, and then do the relocation stuff that you already have.
JPanel pnlArea = new JPanel();
pnlArea .addMouseListener(new MouseAdapter() {
#Override public void mouseEntered(MouseEvent arg0) {
//execute some codes if the mouse pointer has enterd the area.
}
});
I think you just need to clarify to yourself what the behaviour of a mouse hitting a wall would be, in terms of coordinates.
Hopefully this terrible image helps;
Whenever the mouse moves, you want to check if it's in the forbidden region (the region beyond the wall; the no man's land). To do this, just check if the x coordinate (assuming a horizontal wall in this example) of the mouse is beyond its limit (the x coordinate of the wall).
If it is, move the mouse back to the wall, preserving its y value (set its x coordinate to that of the wall)
FOR A CAGE:
The case of having a surrounding, square wall is a little bit more complicated, in terms of where to place the mouse when breaching the wall.
Observe that there are 8 different regions to consider where the mouse could enter the 'forbidden zone', and each boundary should translate the mouse differently.
The coordinate of the boundary corners are in red (and consist of 4 values; xL, xR, yT, yB for left, right, top, bottom respectively)).
The green text in each region describes the conditions that must all be true for the mouse to lie in that region (they're how you detect the mouse must be in that region) where x and y are the mouse coordinates.
You can see that the four 'side' regions involve a simple translation; just altering one of the coordinates of the mouse (the x coordinate for a vertical wall, y for a horizontal wall) to match that of the wall.
The four 'corner' regions can entirely change the mouse coordinate (to their corner coordinate!)
Ok so I am creating a ball tilting game, where you navigate a ball around a maze. The ball works, and is all good in the area however I am having some problems in the maze.
The maze is programmatically created through a .txt file that contains 1's and 0's (1's being walls, and 0's being floor.) I have a for loop that goes through the whole .txt file and places a white(wall) or black(floor) square at the proper coordinates on a canvas. This is similar to the apps-for-android Amazed game if you have seen it link. However, instead of placing wall-type detection on his tiles, he just resets the game and deducts a life point if the user rolls onto a 'void' tile.
However I am looking to have 'walls' and not 'voids'. Where if the ball touches the wall, it doesn't go beyond that point, but can still move freely on the other axis. Unless it hits a corner, of course.
The problem I am having is actually creating this detection. I have tried a number of ways but nothing so far has been successful or useful.
I have tried:
- Have an ArrayList of all of the coordinates of the wall tiles, and every game tick, it checks to see if the ball is touching one. However this just slowed the game down to a crawl and was just extremely terrible.
- Check to see what tile the ball is on, and if it's on a wall tile, to stop it on an axis but let it move freely on the other, however this still didn't work as there were some issues when the ball was to the right of the wall tile, but also under it, it couldnt move up, as the code detected it being under the ball.
And a few other ways but I really cannot remember! It's been a bit hectic.
So, I am asking, if anyone has any experience in this area could they please give me a push in the right direction? Im hoping to have the maze walls sorted by Tuesday however it's looking grim!
If you need any more information, please ask.
Thank you in advance for any and all replies.
Instead of having an ArrayList that you have to iterate over, why not store the maze the same way you do the text file? Use a 2D boolean array filled with true for wall and false for floor, or vice versa.
This simplifies finding a wall considerably. All you have to do is figure out where in your grid the ball is. Then you can just check the cells immediately surrounding it. Even if you include diagonals(which probably isn't necessary for an all-90-degree maze), this equates to checking 8 booleans from an array, basically instant.
As for the axis issue, just stop movement in that direction. No need to freeze a whole axis. For instance, if the wall is right of you, just don't allow x to go higher. No reason to not let it lower unless there's a wall to the left.
This is just a general idea, though. Since it's homework, no code for you ;)
Edit:
The 2D array is just that, a boolean[][] which holds true in each of the spots where you want a wall to be. When you read in your text file, just assign it straight away.
Assuming each line in your text corresponds to an y row, and each 0/1 is the x for that column, when you read a 1, assign map[x][y] = true.
I'm honestly not sure what else you need elaboration on. It's a common format to do simple tile-based maps, though. If you google "2d array tile map", you'll find several resources to help with it.
I'm programming a 2D tile based game in Java like Bomberman (my first game).
I use a 2D array to represent the map where I keep track of walls, walkable spaces, etc. By now I was able to make the player move smoothly swaping sprites depending on the direction key he presses (but not interacting with the background/map, it can walk randomly and get out of the screen).
My problem comes when I want to keep track of the player's position in the array. Logically the character always belongs to only one tile but graphically it can be between two tiles. How can I solve this issue?
I already tried this:
currentTileArrayX = x / tileWidth;
currentTileArrayY = y / tileHeight;
Where x and y are the top-left coordinates of the sprite.
But everything became very buggy because the player's sprites aren't the same size as the tiles.
I had another option in mind that would solve the previous problem: When the player presses a direciton key, move the character to the next tile like an animation. This wouldn't let the player stop in the middle of two tiles... But what if he interrupts it with another key press? How can I stop user's action while the animation is executing? I think this is the easiest solution but I don't know how to implement it.
I already tried to find the solution in other questions but I had no luck. I hope you can help me.
Thanks a lot.
Aaaaaaaaaaaaaaah! Encountering the 'discrete space problem' :) Your logic map is discrete but your UI movements are in the continuous space. I don't the user can actually be in both tiles "at the same time" - visually yes, but never 'internally'. Now you are getting the position of the player and that can be "anywhere" within the tile or "on the boundary" of 2 tiles so to speak...
You have two solutions to this problem, IMO:
Use simple rounding: If the player position is < tile-boundary just keep him on the previous tile. If Greater on the next. Now the problem of boundary - you can use a heuristic, since you shouldn't trust the accuracy of the floating point comparisons (i.e, comparing to 0 is not a good thing to do). So you can try something like this if(currentPosition - boundary <= 0.000000001) then assume it's the next tile else stay on the same one.
Well #Jay beat me to it. So the second one is to actually have a
movement speed defined and move the character that many steps per
'click'/'button press' - but you say you have the problem of key
pressed in "between". I'm guessing if you code is designed like this
then it shouldn't be a problem:
update()
{
calculate(); //update all datastructures/calculations
draw(); //update the visual representation based on calculations
}
update() is a.k.a, gameLoop. I think this should solve your problem...
I'd try to keep the logic part (tile the player belongs to) and the visualization part (animation between tiles) as seperate as possible. My approach would be to have a logical location (tile the player is set on) and a movement speed (which essentially means an amount of time the player isn't allowed to move on to the next tile after moving to a tile). Then the animation from one tile to another would mean that your sprite is always moving towards the screen coordinates of your tile - the time this takes could easily be determined by the movement speed (one full tile movement should take as long as the player has to rest on the current tile).
The only special case would be this "turning around", where you would allow the player to return to the tile he came from at any time, taking only (timeToRecoverOnTile - (timeToRecoverOnTile - timeSinceMovementStarted)).
I once did basically the same thing in AS3, but the concept transfers to Java. I decided to create two main values to help keep track of movement, a Point containing the player's x/y value (by tile), and a direction Point for the movement's direction. Here's some pseudo-code:
if(direction.x == 0 && direction.x == 0) {
if (up) direction.y = -1;
else if (down) direction.y = 1;
else if (left) direction.x = -1;
else if (right) direction.x = 1;
} else {
player.x += direction.x;
player.y += direction.y;
distance--;
if(distance == 0) {
direction.x = direction.y = 0;
distance = tileWidth;
}
}
Obviously, you'd have to tweak that to fit your needs, but that's the basics. Also, tileWidth can be replaced with an integer literal that simply is equal to the width of a single tile.