I'm trying to make a little game, where you have a little cube you can control with the arrows. When the cube intersects with another block object, I want it to go back and stop by the edge of the block object. So basically I want my block to stop when it intersects the block object, instead, it moves a bit in to it, and then when I move it again it jumps back. How can I make it so first checks if it will intersect, and if it will not move into it?
My drawing class extends JPanel and I'm painting with paintComponent.
if(keyCode == e.VK_RIGHT) {
if(xRightCollision()){
hero.x -= xVel;
}
else {
hero.x += xVel;
}
}
So let's say the cube is at the edge of the block object, but it's not intersecting it yet, so I press right and it moves into it, I press right again and it jumps back 5 pixels(xVel = 5).
public boolean xRightCollision(){
for(int i = 0; i < obstacles.size(); i++) {
if (hero.intersects(obstacles.get(i))) {
return true;
}
}
return false;
}
I've actually tried a similar thing with paint() on the JFrame, and since you have to call repaint() there, I could check first and then repaint. I don't really understand how paintComponent works since you can't control when it should be repainted.
Just use a temporary value to check, if the cube intersects with an obstacle, and reset to the original position, if necessary:
if(keyCode == e.VK_RIGHT) {
//backup of the cubes position
int tmp = hero.x;
//move the hero to the right
hero.x += xVel;
if(xRightCollision())
//cube intersects with an obstacle -> restore original position
hero.x = tmp;
}
Related
I have made a game of pong and everything about it is working so far. I did the collisions against the paddles to the ball and it can correctly bounce them away unless it hits the corners.
This is a video of what happens when the ball hits the corner of one of the paddles.
https://drive.google.com/file/d/1nyRzsp5tn5Qvst7kVjtlr_rDNH98avbA/view?usp=sharing
Essentially what you can see happen in the video is the ball hits the the paddle on the left at the corner and it doesn't bounce back it just traverses the paddle downwards and then keeps going and they get a point. Here is my code for the collision testing
public void collision() {
this.width = (float) getBounds().width;
this.height = (float) getBounds().height;
for (int i = 0; i < handler.objects.size(); i++) {
if (handler.objects.get(i).getId() == ID.ball) {
GameObject current = handler.objects.get(i);
if (getBounds().intersects(current.getBounds())) {
current.setVx(current.getVx() * -1);
}
}
}
}
getBounds is an overridden method that just returns a rectangle for both the ball(which is a circle) and the paddle
I am happy to provide more of my code if necessary.
Any help on this would be great, thanks!
You are swapping the velocity direction each time you are hitting the paddle, even when you are still touching the paddle in the next frame. The solution is to swap the velocity direction only when the ball is heading towards the paddle, not when (already) going away. The pseudo code can look like this:
if (GeometryUtil.isDirectionGoingDown(direction)) {
if (GeometryUtil.isBallHittingHorizontalLine(
newPosition,
Ball.RADIUS,
paddleTopLeft,
paddleTopRight)) {
direction = calculateNewDirectionAfterHittingPaddle(
direction,
paddlePosition,
newPosition);
ball.setDirection(direction);
}
}
Here the GeometryUtil.isDirectionGoingDown() method is checking if the ball is actually going down. That way the new direction is only set when this condition returned true. When the direction has been swapped in one frame, the next frame will not swap the direction again because GeometryUtil.isDirectionGoingDown() will return false then.
I have an if statement which checks for collision as such:
if (BallY == y && BallX == x) // check for collision
{
x = 80; // reset x to initial
y = 240; // reset y to initial
z = 100; //reset z to initial
}
I have a for loop inside this if statement as such:
if (BallY == y && BallX == x) // check for collision
{
x = 80; // reset x to initial
y = 240; // reset y to initial
z = 100; //reset z to initial
for (int i=50; i<width; i+=80)
{
fill(250,0,0);
ellipse(i, 50, 70, 70);
}
}
So the point is to draw a line of circles on the top of the screen once the collision occurs. This code however, only draws them for a split second then they disappear. How would I make them stay given that a collision has occurred?
You might want to use a boolean value that tracks whether the ball has collided. Set it to true when you detect a collision, and then check the value to decide what to draw. Here's a simplified example:
boolean drawRed = false;
void draw() {
if (mouseY > height/2) {
drawRed = true;
}
if (drawRed) {
background(255, 0, 0);
}
}
This code draws a gray background by default, but then turns to red if the mouse goes in the lower half of the window. It stays red even if you move the mouse back to the top part.
This is just a simple example, but the idea is the same: use a variable to track the state of the sketch, set that variable when your condition is met, and check that variable to decide what to draw.
By the way, your collision detection is a little bit suspicious. You probably don't want to check whether the ball is at an exact location. Instead you probably want to check whether the ball overlaps some area. Here is a guide on collision detection in Processing that might be useful.
If you still can't get it working, please narrow your problem down to a MCVE instead of posting disconnected snippets or your full sketch. Good luck!
I am trying to get the collision in my game to be exactly perfect. What I am testing is if you hit a wall with the player, you come to a stop. I only implemented the collision code for when the player hits the left side of a wall(when the wall is on the right side of the player). Here is the code.
if(entityOnRight){
if(player.getPositionCorner(SquareMapTuples.BOTTOM_RIGHT).x -
ent.getPositionCorner(SquareMapTuples.BOTTOM_LEFT).x > -.9f)
player.setMovementBooleans(false, false, false, false);
else
player.setMovementBooleans(true, false, false, false);
}
Note: If I go very slow, it will stop the player where I desire it to be stopped, but going fast, it won't do the collision the way I want
Essentially, the code states if the wall is on the right side, it will check the bottom right corner of the rectangle of the player, subtract the bottom left corner of the wall, and check if the distance between the two is 0.001. 0.001 is almost an unnoticeable distance, hence why I used that value. Here is the code for player.setMovementBooleans
public void setMovementBooleans(boolean canMoveRight, boolean canMoveLeft, boolean canMoveUp, boolean canMoveDown){
this.canMoveRight = canMoveRight;
if(canMoveRight == false && moveRight)
vel.x = 0;
}
The canMoveRight boolean in the Player class (not in parameters) is what allows you to be able to move, moveRight is when you are trying to move right. Here is some code that will better explain how these booleans interact:
//If you clicked right arrow key and you're not going
//Faster then the max speed
if(moveRight && !(vel.x >= 3)){
vel.x += movementSpeed;
}else if(vel.x >= 0 && !moveRight){
vel.x -= movementSpeed * 1.5f;
System.out.println("stopping");
//Make sure it goes to rest
if(vel.x - movementSpeed * 1.5f < 0)
vel.x = 0;
}
and:
if(Gdx.input.isKeyPressed(Keys.D) && canMoveRight)
moveRight = true;
else
moveRight = false;
So to give a summary, if you click the "D" key, it allows you to start moving. However if the boolean canMoveRight is false, it won't move you. Here is an image showing what happens (The player is yellow, the wall is green)
As you can see, the player goes much further then I want it to. It should stop at this point:
Any help with figuring out how to accomplish this is extremely appreciated!
Maybe the way you tried it is a bit too complicated :-). I suggest a simpler way from scratch: make the map and the player a com.badlogic.gdx.math.Rectangle instance. Now, in the following part of the code you make a check, whether after the move the player would still be inside the map, if yes then allow the move, if not, then don't allow:
if(Gdx.input.isKeyPressed(Keys.D){
float requestedX, requestedY;
//calculate the requested coordinates
Rectangle newPlayerPositionRectangle = new Rectangle(requestedX, requestedY, player.getWidth(), player.getHeight());
if (newPlayerPositionRectangle.overlaps(map) {
//move the player
} else {
//move the player only to the edge of the map and stop there
}
}
The best way to handle those collisions would be to use a physics engine like Box2D which already comes packed with Libgdx. When a collision occurs in Box2D a event gets fired and you can easly handle that event. So you should probably take a look here.
Another alternative to achieve this without physics would be to use logical rectanlges representing the player and walls (can also be polyline) and use Intersector class of libgdx.
which is here.
i'm quite stuck. Before I do anything, heres the code:
if(inAir&&!falling&&!jumping){
if(py<600){
if (!(isBlocked(xminusd, py) || isBlocked(xminus, py + 32 - 1))) {
falling=true;
}else{
py-=2;
inAir=false;
}
}
}
for(int g = 0;g<Map.r.size();g++){
if(rect.intersects(Map.r.get(g))||Map.r.get(g).contains(rect)||rect.contains(Map.r.get(g))||Map.r.get(g).intersects(rect)){
System.out.println("Intersecting!");
inAir= false;
hasjumped=false;
onPlat = true;
falling = false;
jumping = false;
py-=4;
break;
}else{
onPlat = false;
if(inAir==false&&!onPlat){
inAir = true;
onPlat = false;
}
}
}
Now the problem is, i'm trying to make collision detection with a certain type of tile, by creating rectangles for each tile, and if the player collides with it it stops all movement.(falling wise at least). But i've run into a problem. I've used an array list, to create all my rectangles, and i'm using a for loop to check each rectangle. Problem is, if it checks a rectangle and i'm not colliding with that rectangle currently, it immidiatly starts falling, then resetting, because it finds the rectangle i'm colliding with. The problem is im using a for loop to cycle through each rectangle... I'm really stuck on how to do collision detection with platform tiles. Anyone have any help to provide? Please be descriptive.
It doesn't look like it matters which rectangle you are colliding with so try abstracting by making a function that returns true or false if it is colliding with any block and put that in your else if statement. that way if you are still colliding it wont start falling while cycling through the rest of your blocks
Something like
...
if(colliding())
{
//stop falling
}
else
{
//start falling
}
....
boolean colliding(){
for(int g = 0;g<Map.r.size();g++){
//check for collision if true return true
}
return false;
}
EDIT:
The reason this works is because as you are going through the for loop it keeps the object falling while it determines that it should stop. By moving the falling logic away from the collision logic we can determine if it is colliding and then take the appropriate action.
I'm working on a tile 2d-side platformer game. I have done some stuff so far.
I'm working on a basic collision detection using rectangles of libgdx so considering
I have only grass block for now I made a single block world in Java (file reader is not ready)
the problem is my detection only works the first time in other words if I spawn my colliding
to a block it detects collision and do so. Although if i spawn my player top of the block
with out colliding player falls forever.
Here is the code world.update(); =>
public void update() {
Iterator<block> cb = Blocks.iterator();
while (cb.hasNext()) {
block b = cb.next();
if (b.getBounds().overlaps(player.getBounds())) {
if (player.getPosition().x >= b.getPosition().x + 32) {
//RIGHT
player.getVelocity().x = 0;
} else if (player.getPosition().x + 32 <= b.getPosition().x) {
//Left
player.getVelocity().x = 0;
}
//All Y
player.getVelocity().y = 0;
}
if (!b.getBounds().overlaps(player.getBounds())) {
player.getVelocity().y = -gravity;
}
}
}
Your while loop is applying gravity for every block your player does not intersect with. So if you have 10 blocks, and the player intersects just 1, you'll still apply gravity 9 times. You should only apply the gravity change to the player once.
Set a flag (boolean hitSomething = false) before your loop, then set it to true (hitSomething = true) if the player hits any block. Then, after the loop, if hitSomething is false, apply gravity to the player.
Stepping through the update method with a debugger is a good way to figure out what your code is doing in cases like this. It should be quicker than waiting for Stack Overflow to debug your code, too.