I'm trying to think of a way to efficiently and neatly determine whether a valid move is being made with a bishop in chess.
The piece will be moved from srcX,srcY to dstX,dstY
This is part of one of my ideas:
if(srcX < dstX && srcY < dstY) {
// Moving towards the top right of the board
// Determine the decrease in X coordinate
int deltaX = dstX-srcX;
// If the move is valid, the Y coordinate will have decreased by the same number as X
int validY = dstY-deltaX;
if(validY == srcY) {
validMove = true;
}
}
but it's going to be a bit long winded, doing that for ever corner.. Can anyone think of a nicer way?
I would break it up into two steps.
1) Is it a valid destination?
2) Are there obstructions?
The first is easy to calculate. Since a bishop can only move diagonals the deltaX and deltaY must be equal.
So, if( abs(srcX-dstX) == abs(srcY-dstY) )
That rules out logically invalid moves.
Then it is a simple matter iterating through the positions in between as you have done to check for obstructions.
If it's a diagonal the x and y move shoudl be the same, so...
return Math.abs(srcx - dstx) == Math.abs(srcy - dsty);
The move is valid if:
Destx-Desty = SourceX - SourceY OR
16 - DestX- DestY = SourceX - SourceY
Related
I'm making a 2d game in libgdx and I would like to know what the standard way of moving (translating between two known points) on the screen is.
On a button press, I am trying to animate a diagonal movement of a sprite between two points. I know the x and y coordinates of start and finish point. However I can't figure out the maths that determines where the texture should be in between on each call to render. At the moment my algorithm is sort of like:
textureProperty = new TextureProperty();
firstPtX = textureProperty.currentLocationX
firstPtY = textureProperty.currentLocationY
nextPtX = textureProperty.getNextLocationX()
nextPtX = textureProperty.getNextLocationX()
diffX = nextPtX - firstPtX
diffY = nextPtY - firstPtY
deltaX = diffX/speedFactor // Arbitrary, controlls speed of the translation
deltaX = diffX/speedFactor
renderLocX = textureProperty.renderLocX()
renderLocY = textureProperty.renderLocY()
if(textureProperty.getFirstPoint() != textureProperty.getNextPoint()){
animating = true
}
if (animating) {
newLocationX = renderLocX + deltaX
newLocationY = renderLocY + deltaY
textureProperty.setRenderPoint(renderLocX, renderLocY)
}
if (textureProperty.getRenderPoint() == textureProperty.getNextPoint()){
animating = false
textureProperty.setFirstPoint(textureProperty.getNextPoint())
}
batch.draw(texture, textureProperty.renderLocX(), textureProperty.renderLocY())
However, I can foresee a few issues with this code.
1) Since pixels are integers, if I divide that number by something that doesn't go evenly, it will round. 2) as a result of number 1, it will miss the target.
Also when I do test the animation, the objects moving from point1, miss by a long shot, which suggests something may be wrong with my maths.
Here is what I mean graphically:
Desired outcome:
Actual outcome:
Surely this is a standard problem. I welcome any suggestions.
Let's say you have start coordinates X1,Y1 and end coordinates X2,Y2. And let's say you have some variable p which holds percantage of passed path. So if p == 0 that means you are at X1,Y1 and if p == 100 that means you are at X2, Y2 and if 0<p<100 you are somewhere in between. In that case you can calculate current coordinates depending on p like:
X = X1 + ((X2 - X1)*p)/100;
Y = Y1 + ((Y2 - Y1)*p)/100;
So, you are not basing current coords on previous one, but you always calculate depending on start and end point and percentage of passed path.
First of all you need a Vector2 direction, giving the direction between the 2 points.
This Vector should be normalized, so that it's length is 1:
Vector2 dir = new Vector2(x2-x1,y2-y1).nor();
Then in the render method you need to move the object, which means you need to change it's position. You have the speed (given in distance/seconds), a normalized Vector, giving the direction, and the time since the last update.
So the new position can be calculated like this:
position.x += speed * delta * dir.x;
position.y += speed * delta * dir.y;
Now you only need to limit the position to the target position, so that you don't go to far:
boolean stop = false;
if (position.x >= target.x) {
position.x = target.x;
stop = true;
}
if (position.y >= target.y) {
position.y = target.y;
stop = true;
}
Now to the pixel-problem:
Do not use pixels! Using pixels will make your game resolution dependent.
Use Libgdx Viewport and Camera instead.
This alows you do calculate everything in you own world unit (for example meters) and Libgdx will convert it for you.
I didn't saw any big errors, tho' i saw some like you are comparing two objects using == and !=, But i suggest u to use a.equals(b) and !a.equals(b) like that. And secondly i found that your renderLock coords are always being set same in textureProperty.setRenderPoint(renderLocX, renderLocY) you are assigning the same back. Maybe you were supposed to use newLocation coords.
BTW Thanks for your code, i was searching Something that i got by you <3
I've finally completed the collision detection, however the collision response is very glitchy (if you try you can go through walls) and that's mainly because I have no information about the collision angle!
I have camPos(x,y,z) coordinates of my camera aswell as the min and max values of model(minX,minY,minZ,maxX,maxY,maxZ).. with a simple test I check if the camPos is interecting the model boundaries:
if(cameraX > xMax || cameraX < xMin) {
collisionX = false;
collisionY = false;
collisionZ = false;
} else {
collisionX = true;
System.out.println("collisionX: "+ collisionX); // collision on x is true!
}
I have acess to all vertice positions and calculated the min max values of the object to create a BoundingBox.
In order to get the right direction in which I want to push the object I need to know in which direction the nearest face is pointing (left,right,forward,back?)
To find out the angle I thought I could use the normal coordinates which I also have acess to, since they indicate a 90 degree angle to the face, right?
console print: //all 'vn' values of cube.obj
xNormals:0.0
yNormals:0.0
zNormals:0.0
xNormals:0.0
yNormals:0.0
zNormals:0.0
xNormals:1.0
yNormals:1.0
zNormals:1.0
xNormals:0.0
yNormals:0.0
zNormals:0.0
xNormals:-1.0
yNormals:-1.0
zNormals:-1.0
xNormals:0.0
yNormals:0.0
zNormals:0.0
Basically I want to know how these normal coordinates have to be applied to the min and max values of the object so that I can define all faces of the BoundingBox for example: face A is defined by xMin_a and xMax_a and faces left, face B is defined by xMin_b and xMax_b and faces right and so on..
I hope it's a bit more understandable, it's quite hard to explain..
Okay I've figured out a way to do it, hope it will help someone else too: I found out how to calculate the faces of a bounding box, it was actually not even that hard and it had absolutely nothing to do with normals.. sorry for the confusion.
As shown in my answer you can calculate the boundingBox of objects with their min/max values.. but you can also define all six faces of the box by extending the check and use a boolean to find out if the respective face collides somewhere:
if(collisionX == true && collisionY == true) {
if(cameraZ+0.2 > zMin_list.get(posIndex)-0.2 && cameraZ+0.2 < zMin_list.get(posIndex)) {
faceA = true;
System.out.println("faceA = " +faceA + " face a is true!");
} else {
faceA = false;
}
}
You can do this for all six faces where A(Forward), B(Back), C(Left), D(Right), E(Up) and F(Down) will define where the collision direction should be:
If the collision is on Face A, the response will be moving backwards (on z axis minus).. That way you will never be able to glitch through a wall because it will always push you away from the collision area.
I'm making a 2D game, nothing fancy, with objects (called entities from now on) that should collide with eachother and terrain. Now, detecting collision is not the problem, the problem is when the entities collide with the terrain.
I have a simple .png, upon loading the game I go through all pixels of this image and add all black ones to a list, these are the pixels that is collidable.
Collision-code from Entity-class:
int ceiling = Integer.MAX_VALUE;
int floor = 0;
int rightPoint = 0;
int leftPoint = Integer.MAX_VALUE;
for(Point p : main.terrain.points)
if(getHypoRect().contains(p))
{
if(p.x > rightPoint && right)
rightPoint = p.x;
if(p.x < leftPoint && left)
leftPoint = p.x;
if(p.y < ceiling && up)
ceiling = p.y;
if(p.y > floor && down)
floor = p.y;
}
if(rightPoint != 0)
xCoord = rightPoint - sprite.getImage().getWidth();
else if(right)
xCoord+=speed;
if(leftPoint != Integer.MAX_VALUE)
xCoord = leftPoint;
else if(left)
xCoord-=speed;
if(ceiling != Integer.MAX_VALUE)
yCoord = ceiling;
else if(up)
yCoord-=speed;
if(floor != 0)
yCoord = floor - sprite.getImage().getHeight();
else if(down)
yCoord+=speed;
In the for-loop I go through all points (black pixels) in the terrain, then check if the Entity's collisionbox contains them (speed is added in this method, or rather "hypothetically" added, that's why it has the weird name).
Now, if the x-value of the point is greater than the "rightpoint", and if the Entity is walking to the right, it's overwritten. The same happens with leftPoint ("leftest" point), ceiling and floor.
Then I check if any of these points have been changed, if they have that means we collided with the terrain so we bounce them back. For example, say the Entity is walking to the right and we collided with the terrain, rightPoint have been written with the "rightest" point we collided with so then we set the coordinate so that the Entity is right beside the point that it collided with.
If one would only go at one direction at a time, this would work perfectly, but "weird" things happen when you take multiple inputs into account.
Example: the Entity walks, flat to the floor, towards a ledge on the right, when the Entity is halfway over the ledge, it wants to go down, so both right and down are pressed, what my code will do is check the inputs, put the Entity where it wants to be and then bounce it back if it hit terrain, so it will see that I press right and bounce the Entity back to the end of the ledge.
This is all my own idea of how terraincollision could work, I couldn't find anything online except how to check if a collision took place, but nothing that covers this.
Any idea what could make my solution work, or a pointer to how terraincollision should be done?
Your bouncing back idea maybe problematic. Try instead to ignore moves that would collide with the terrain:
If the player moves down and right, then first check if down would collide, if yes, then ignore that movement, and check for right, if right is possible do right movement, else block, too.
I am trying to write small program to check if one rectangle contains second rectangle and distance betwwen their borders should be less than some specific number like 100 or 50.
When I use Rectangle.contains method it doesnt care about about distnce between borders of both rectangle.
Is there any way this can be achieved?
You could use the contains(Rectancle r) method twice: first to check if the inner rectangle is inside the outer rectangle at all, then temporarily enlarge the inner rectangle by half the threshold into every direction and make the same check again. This time it shouldn't be inside the outer rectangle anymore. So basically something like this:
//Rectangle outer; // Do some proper setup for these two
//Rectangle inner;
int limit = 50;
boolean containsWithinLimits = outer.contains(inner);
inner.setLocation(inner.getX()-limit/2, inner.getY()-limit/2);
inner.setSize(inner.getWidth()+limit, inner.getHeight()+limit);
boolean containsWithinLimits = containsWithinLimits && !outer.contains(inner);
// Now reset the bounds:
inner.setLocation(inner.getX()+limit/2, inner.getY()+limit/2);
inner.setSize(inner.getWidth()-limit, inner.getHeight()-limit);
example code etc?
Even so, you'll want to do the following:
unless im mistaken.
pseudo code:
rectA = outside, rectB = inside
if rectB.left - rectA.left < x then distance is ok else do something
if rectB.top - rectA.top < y then distance is ok else do something
etc etc
If the rectangles are orthogonal, and I assume that you have called contains(Rectangle rect). Then you only have to do extra comparisons:
inside.x - outside.x >= LEFT_BORDER &&
outside.x + outside.width - inside.x - inside.width >= RIGHT_BORDER &&
inside.y - outside.y >= TOP_BORDER &&
outside.y + outside.height - inside.y - inside.height >= BOTTOM_BORDER
LEFT_BORDER, RIGHT_BORDER, TOP_BORDER, BOTTOM_BORDER are for you to define.
In Rectangle2d ,we are having
boolean contains(double x, double y)
--- Tests if a specified coordinate is inside the boundary of this Rectangle2D.
boolean contains(double x, double y, double w, double h)
--- Tests if the interior of this Rectangle2D entirely contains the specified set of rectangular coordinates.
So it is not possible to check about the distance to my knowledge...
I am working on a game in which you are a simple circle that fires bullets and its multiplayer and so on. Well, I am trying to make boundaries sort of like a maze type thing that u have to go through I have tried collision detection like this:
public void checkCollisions(){
Rectangle r1 = bo.getBounds();
Rectangle d = p.getBounds();
if (d.intersects(r1))
border = true;
}
And basically if border = true then i stop the character from moving. I have 2 problems when i do this,
He doesnt stop just goes REALLY slow.
He stays at the REALLY slow state even off the border.
I use border like this:
boolean border = false;
then in my paint method i state this:
if (border)
p.dx = 0;
p.dy = 0;
p represents the Guy class :P
More of the dx and dy:
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_A)
dx = -2;
if (key == KeyEvent.VK_D)
dx = 2;
if (key == KeyEvent.VK_W)
dy = -2;
if (key == KeyEvent.VK_S)
dy = 2;
and for keyReleased i just change the value of dx and dy to 0
also for how the guy moves:
public void move() {
x = x + dx;
y = y + dy;
}
Please help me figure out why this isn't working.
OK, I still think a full restructuring of your game logic is in order, but I think I can shed light as to what's going on. Let's look at the various places where things are happening:
PAINT: On the Swing thread, when paint() is called, you see if there were collisions and if so zero out the speeds (assuming you fix that if block).
KEY: On the Swing thread, when a key is pressed, you set the speed according to the key pressed.
CHECK: At some unknown point, you check for collisions and record whether there was one.
MOVE: At some unknown point, you update your "guy's" position with the speed.
So here's the problem: in Java, just like any other program, you get multiple key pressed events when you're holding down a key. There will be a short delay between the first and second, and then they will repeat rapidly. Try it in a text box in your browser, the same behaviour occurs there.
So how does that affect you? Well, you're probably getting into a scenario like this:
PAINT -> speed set to zero
KEY -> speed set back to -2
MOVE -> guy is moved -2
CHECK -> border = false
PAINT -> speed set to zero again
Really, if you restructure the code so that you get a game loop that looks something like this:
public void runGame() {
while(true) {
updateSpeeds();
updatePositionFromSpeed();
repaint();
}
}
Where updateSpeeds() would instead query whether the key is down or up and also compute whether the guy could move in that direction, and updatePositionFromSpeed() would update the guy's position. Then paint() would rely only on the guy's x and y coordinates, would not write to them, and would not need to know about the speed.
here's a very easy solution.
Here's a bit of my pseudo code.
if(player.getBounds().intersects(wall.getBounds())){
//Go Back to prior position, regardless of direction coming from. Since the reverse velocity X and velocity Y directions are taken care off
x -= velX;
y -= velY;
//Then Stop at that prior position to make next move
velX = 0;
velY = 0;
}