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!)
Related
Lets say I have a circle, and if the user drags his mouse clockwise along the path of the circle the counter increases, and if he drags the mouse counter-clockwise it decreases. What is the best way to implement this in Java? I imagine trig will be needed so the program knows when the user is dragging clockwise or counter-clockwise, right? Not looking for code examples, just help with theory so I can begin with the right approach.
As you probably have access to the circle, get its center point coordinates.
Then get the coordinates of the mouse. After that you compute the angle between the vector and the x-axis.
You do so by first setting the circle point as the center of the imaginary coordinate system and then shifting the mouse coordinates to this system. After that you apply atan2 on the new mouse coordinates. The result is the desired angle.
Point center = ...;
Point mouse = ...;
Point shiftedMouse = new Point(mouse.x - center.x, mouse.y - center.y);
double angle = Math.atan2(shiftedMouse.y, shiftedMouse.x);
At this point you probably need to convert the result of angle to degrees or something like that, if you like. You may take a look at Wikipedia#atan2 for this.
Of course you can also leave it in the format (-pi, pi] and work with that, if you know what it means.
Now you track how this angle changes. If it increases, then the mouse is moving counter-clockwise; if it decreases, then clockwise and so on (or maybe the other way around, just try it). Take care of the bound where after 359° 0° and then 1° comes.
Firstly, apologies for the long title; I could not think of a way to sufficiently cover my problem yet also compact it further.
I am in the process of creating a 2D game in Java with a character in the centre of the screen. My character has a collision box and I have images on the map (looking from above) which also have collision boxes.
However, I'd like to be able to have a "slide" situation if a collision occurs into a side that is not perpendicular to my direction.
For example, if my character is moving east, and there is a wall to his east going in the southwest to northeast direction, instead of just noting that there is an object to the east and not moving, I'd like my character to be able to "slide" along the wall, moving northeast to achieve the attempted Eastern movement.
Is there any easy way to do this?
If it helps in any way, I am using Java Slick2D, and have the collision box of the character as a rectangle where he stands, and the collision boxes of other objects as polygons.
Thanks in advance for any replies!
When you have solved the problem of identifying when a collision has occurred, the sliding motion can be achieved by calculating the component of the motion that is perpendicular to the wall and subtract that from your motion vector.
Say you have a motion vector v = (v_x, v_y) and the normal of the wall n = (n_x,n_y). The normal vector should be of length 1.
Then your new motion vector should be
v_new = v - (v * n) * n.
That in X and Y separately is
v_new_x = v_x - (v_x * n_x + v_y * n_y) * n_y,
and the same way for Y
Class java.awt.geom.Area has a method intersects( Area a ) which should be useful for determining the "point" of impact, call it P. If the character's collision box is a rectangle and the obstacle is bounded by an arbitrary polygon you'll have to determine
the point or side of the rectangle participating in the collision
the point or side of the polygon participating in the collision
If side meets side (they should be parallel), the charcter can't move any more in the current direction; no slide should occur. Equally, if a rectangle side meets a polygon point, movement is blocked.
If a point meets a point, you might resolve this by (arbitrarily?) select one of the sides of the polygon and handle the situation based on that.
Finally, if a rectangle corner meets a slanting side, you'll have to analyze the geometry of this side. (Verify that a 10-to-4 side is met by the upper right (lower left) hand corner if going north or east (south or west), or a 7-to-1 side is met by the upper left (lower right) hand corner when going north or west (south or east)). Then you can determine the forced path along the slanted side.
While this sounds relatively simple, there may be much more complex situations lurking literally round the corner if the collision boxes of objects - polygons - may have concave sections.
I am working on a simple 2D game with Java, swing and no framework. I have a rectangular player that the user can move around. On the map are few obstacles which the player should not be able to go through. I did this by making a new Rectangle Object for the player and each obstacle with their bounds. But I’m not really sure if this is the right way to do it. It works but the movements of the player are not really user friendly. If the player wants to pass two obstacles they must be on the perfect coordinates to pass.
Is it even a good idea to check for intersections between the player and the obstacle with a Rectangle object or should I do it another way?
Now for my 2nd question:
I’d like to replace the rectangular hitboxes with the same hitbox but with rounded corners so the player could pass more easily.
This is what the game looks like with hitboxes enabled.
The code that checks if the player and the obstacles have yet intersected:
for (Player p : this.getPlayerArray()) {
Rectangle recPlayer = p.playerBounds();
for (Obstacle kiste : obstacleArray) {
Rectangle recKiste = kiste.obstBounds();
if (recPlayer.intersects(recKiste)) {
p.setX(100); //Not actual code here
}
}
}
The function that returns the hitbox of the player / obstacle:
public Rectangle obstBounds() {
return new Rectangle(this.getX(),
this.getY(), image.getImage().getWidth(null),
image.getImage().getHeight(null));
}
Many years ago I wrote a Khepera simulator as part of my undergrads' final year project. I started by doing collision detection as you are doing, that is intersecting areas... My supervisor made me notice that since the shape of my robot was a circle I just could check if the center of the robot was inside another shape, if that was the case a collision occured.
Your case is even simpler since you move on tiles... so either you do (as suggested in the comments) maintain a set of "move/no move" tiles and check that, or you just check that the position of your player is within, or not, a 'forbidden' rectangle, i.e. an obstacle. If it is, then you have to reset the position of the character to be 'outside' of the obstacle (minus the character's bounding box, obviously)
I strongly suggest to do it the tiles way: allow only up/down/left/right movements and check against a 'forbidden' set of movements given a tile-position. If you really want 'freedom' of movements than go with circles (bounding boxes/circles) because they are easy to reason with, easy to do a position reset (in case of collisions) and perfect for your case (every tile can contain a circle, whether an obstacle or the player.)
There are many ways to go about collision checking, but I think a simple approach would do just fine for your use-case.
First from the looks of your screenshot, a tile is either an obstacle or passable, but never half of each. In that case it would be simplest to just check on which tile the center (or feet, choose what looks best) of the character are.
If its an obstacle, they cant go there, simple as that. Note that this will allow the player to move partially into an obstacle, but many games do it this way and players are certainly used to this behavior, especially in 2D games with graphics designed to look like an isometric projection (which I would yours class as). A variation of this would be to simply make the player collision rectangle smaller (say half a tile, again centered at the player sprites chest or feet).
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'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.