Hey guys i'm making a maze game and I'm trying to figure out how to make a 2D collision smooth. Currently I have some really bad collision code that I thought up since I haven't done this part yet and it is glitchy and sometimes goes inside the wall then you can't get out.
My code:
public void checkCollision() {
Rectangle player_rectangle = new Rectangle(player.getX(),player.getY(),32,32);
for(Wall wall : walls) {
Rectangle wall_rectangle = new Rectangle(wall.getX(), wall.getY(), 32,32);
if(player_rectangle.intersects(wall_rectangle)) {
if(player.xspeed == 1) {
player.xspeed = 0;
player.x -= 1.2;
} else {
if(player.xspeed == -1) {
player.xspeed = 0;
player.x += 1.2;
}
else
if(player.yspeed == 1) {
player.yspeed = 0;
player.y -= 1;
} else {
if(player.yspeed == -1) {
player.yspeed = 0;
player.y += 1;
}
}
}
}
}
}
What is a better way to do the collision? here is a picture of the types of maps I will have:
EDIT:
New Collision code:
if (player_rectangle.intersects(wall_rectangle)) {
Rectangle intersection = (Rectangle) player_rectangle.createIntersection(wall_rectangle);
if (player.xspeed > 0) {
player.x -= intersection.getWidth();
}
if (player.yspeed > 0) {
player.y -= intersection.getHeight();
}
if (player.xspeed < 0) {
player.x += intersection.getWidth();
}
if (player.yspeed < 0) {
player.y += intersection.getHeight();
}
Print(Integer.toString(intersection.width) + ", " + Integer.toString(intersection.height));
}
Movement Code:
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_LEFT) {
xspeed = -1;
} else {
if(key == KeyEvent.VK_RIGHT) {
xspeed = 1;
} else {
if(key == KeyEvent.VK_UP) {
yspeed = -1;
} else {
if(key == KeyEvent.VK_DOWN) {
yspeed = 1;
}
}
}
}
}
Thanks for any help you can give me.
You can use Rectangle.createIntersection(Rectangle).
If the player moves to a positive direction, just subtract the width and height of the resulting Rectangle from his position, if he moves to a negative, add them.
Don't set the speed to zero, this could cause the player to hang.
EDIT
if (playerRectangle.intersects(wallRectangle) {
Rectangle intersection = (Rectangle) playerRectangle.createIntersection(wallRectangle);
if (player.xspeed > 0) {
player.x -= intersection.getWidth();
}
if (player.yspeed > 0) {
player.y -= intersection.getHeight();
}
if (player.xspeed < 0) {
player.x += intersection.getWidth();
}
if (player.yspeed < 0) {
player.y += intersection.getHeight();
}
}
EDIT2
As far as I know, keyPressed is only triggered when you press a key, and not when you release it. Try it like this:
private boolean up, down, left, right;
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KEyEvent.VK_UP) {
up = true;
}
...
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KEyEvent.VK_UP) {
up = false;
}
...
}
// Call this in the mainthread
public void updateMovement() {
if (up) {
player.xspeed = 1;
}
...
}
So in every frame, you update the movement, move the player and then check the collision.
Related
Diagonal lines where one in the middle repeats (the problem line)
The code is meant to make alternating lines of white and red, but after it switches at the halfway point (once it can't go north), it repeats the first color again.
public void pattern1(String color, String color2) {
setPaint(1000);
int I=1;
int C=1; /* which color*/
moveTo(0,0);
moveSouth();
paint(color);
C = 2;
int X = getX();
int Y = getY();
while (getMyPaint() != 744) {
if (canMove("north")){
while (canMove("north")) {
while (C == 1){
if (!canMove("west")) {
X = X+1;
moveTo(X,Y);
C = 2;
}
if (canMove("west")) {
while (canMove("west")) {
makeTurn("north");
paint(color);
move();
makeTurn("west");
move();
paint(color);
}
}
}
while (C == 2){
if (!canMove("west")) {
X = X+1;
moveTo(X,Y);
C = 1;
}
if (canMove("west")) {
while (canMove("west")) {
makeTurn("north");
paint(color2);
move();
makeTurn("west");
move();
paint(color2);
}
}
}
}
}
if (!canMove("north")) {
X=getX();
Y=getY();
X = X+1;
moveTo(X,Y);
while (canMove("south")){
while (C == 1){
if (!canMove("east")) {
X = X+1;
moveTo(X,Y);
C = 2;
}
if (canMove("east")) {
while (canMove("east")) {
makeTurn("south");
paint(color);
move();
makeTurn("east");
move();
paint(color);
}
}
}
while (C != 1){
if (!canMove("east")) {
X = X+1;
moveTo(X,Y);
C = 1;
}
if (canMove("east")) {
while (canMove("east")) {
makeTurn("south");
paint(color2);
move();
makeTurn("east");
move();
paint(color2);
}
}
}
}
}
}
}
}
The problem occurs in the if(!canMove("north")), if you know what the issue is, please let me know
i've got an issue with my breakout game in java. Everything works well other than my paddle going off the screen on the right side, my ball does this too, but not worried about that right now.
// prevent paddle from moving outside of the screen
Public void update() {
x += xVelocity;
if (x <= 0) {
setX(0);
xVelocity = -1;
}
if (x >=
(Settings.WINDOW_WIDTH
- Settings.PADDLE_WIDTH) {
setX(Settings.WINDOW_HEIGHT
- Settings.PADDLE_HEIGHT);
xVelocity = 1;
}
// set velocity depending on pressing left or right
Public void keyPressed(KeyEvent e)
if (e.getKeyCode() ==
KeyEvent.VK_LEFT) {
paddle.setXVelocity(-1);
} else if (e.getKeyCode() ==
KeyEvent.VK_RIGHT) {
paddle.setXVelocity(1);
}
}
// set velocity after keys released
Public void keyReleased(KeyEvent e)
if (e.getKeyCode() ==
KeyEvent.VK_LEFT) {
paddle.setXVelocity(0);
} else if (e.getKeyCode() ==
KeyEvent.VK_RIGHT) {
paddle.setXVelocity(0);
}
}
How do i get the paddle to
stay on screen on the right
side?
Any help appreciated
Change this
if (x <= 0) {
setX(0);
xVelocity = -1;
}
if (x >=
(Settings.WINDOW_WIDTH
- Settings.PADDLE_WIDTH) {
setX(Settings.WINDOW_HEIGHT
- Settings.PADDLE_HEIGHT);
xVelocity = 1;
}
to this
if (x <= 0) {
setX(0);
xVelocity = -1;
}
if (x >= (Settings.WINDOW_WIDTH - Settings.PADDLE_WIDTH) {
setX(Settings.WINDOW_WIDTH - Settings.PADDLE_WIDTH);
xVelocity = 1;
}
When you check if the value of x is within the difference of window width and paddle width, the new value of x should be set as the difference of window width and paddle width, NOT the difference between window height and paddle height.
I want the ball.move(); function in the code below to continue running after pressing space once. It only works if I continue pressing the space key.
void draw() {
if (start == true) {ball.move();}
}
void keyPressed() {
if (key == ' '){start = true;}
}
void keyReleased() {
if (key == ' ') {start = false;}
}
It's for a Pong game I am making and each time the ball hits the edge it is teleported to the center of the canvas. That´s when I want to be able to start the ball movement manually again.
Here is the whole code:
Ball ball;
Player player1;
Player player2;
int scorePlayer1 = 0;
int scorePlayer2 = 0;
PFont font;
boolean start;
void setup() {
size(1368,768);
frameRate(144);
noStroke();
ball = new Ball(width/2, height/2, 30);
player1 = new Player(15, height/2, 30, 150);
player2 = new Player(width-15, height/2, 30, 150);
ball.speedX = 10;
}
void draw() {
background(0);
textSize(40);
textAlign(CENTER);
font = loadFont("Arial-Black-48.vlw");
textFont(font);
ball.display();
if (start == true) {ball.move();}
player1.run();
player2.run();
//Score
if (ball.left() < 0) {
scorePlayer2 = scorePlayer2 + 1;
ball.x = width/2;
ball.y = height/2;
}
if (ball.right() > width) {
scorePlayer1 = scorePlayer1 +1;
ball.x = width/2;
ball.y = height/2;
}
text(scorePlayer1, width/2-75, 50);
text(scorePlayer2, width/2+75, 50);
//Collision
if (ball.top() < 0) {
ball.speedY = -ball.speedY;
}
if (ball.bottom() > height) {
ball.speedY = -ball.speedY;
}
if (ball.left() < player1.right() && ball.y > player1.top()-10 && ball.y < player1.bottom()+10) {
ball.speedX = -ball.speedX;
ball.speedY = map(ball.y - player1.y, -player1.h/2, player1.h/2, -5, 5);
}
if (ball.right() > player2.left() && ball.y > player2.top()-10 && ball.y < player2.bottom()+10) {
ball.speedX = -ball.speedX;
ball.speedY = map(ball.y - player2.y, -player2.h/2, player2.h/2, -5, 5);
}
if (player1.bottom() > height) {
player1.y = height-player1.h/2;
}
if (player1.top() < 0) {
player1.y = player1.h/2;
}
if (player2.bottom() > height) {
player2.y = height-player1.h/2;
}
if (player2.top() < 0) {
player2.y = player1.h/2;
}
}
//Movement
void keyPressed() {
player1.pressed((key == 'w' || key == 'W'), (key == 's' || key == 'S'));
player2.pressed((keyCode == UP), (keyCode == DOWN));
if (key == ' '){start = true;}
}
void keyReleased() {
player1.released((key == 'w' || key == 'W'), (key == 's' || key == 'S'));
player2.released((keyCode == UP), (keyCode == DOWN));
if (key == ' ') {start = false;}
}
class Ball {
float x;
float y;
float d;
float speedX;
float speedY;
color c;
//Constructor
Ball(float tempX, float tempY, float tempD){
x = tempX;
y = tempY;
d = tempD;
speedX = 0;
speedY = 0;
c = (255);
}
void display() {
fill(c);
ellipse(x,y,d,d);
}
void move() {
x = x + speedX;
y = y + speedY;
}
//Collision help
float top() {
return y-d/2;
}
float bottom() {
return y+d/2;
}
float left() {
return x-d/2;
}
float right() {
return x+d/2;
}
}
class Player {
float x, y;
float w, h;
float speedY = 0.0;
color c;
boolean moveUp = false, moveDown = false;
//Constructor
Player(float tempX, float tempY, float tempW, float tempH){
x = tempX;
y = tempY;
w = tempW;
h = tempH;
speedY = 0;
c = (255);
}
void run() {
display();
move();
}
void display() {
fill(c);
rect(x-w/2, y-h/2, w, h);
}
//Movement
void move() {
if (!moveUp && !moveDown) {speedY = speedY * 0.85;}
if (moveUp) {speedY -= 1;}
if (moveDown) {speedY += 1;}
speedY = max(-7.0, min(7.0, speedY));
y += speedY;
}
void pressed(boolean up, boolean down) {
if (up) {moveUp = true;}
if (down) {moveDown = true;}
}
void released(boolean up, boolean down) {
if (up) {moveUp = false;}
if (down) {moveDown = false;}
}
//Collision help
float top() {
return y-h/2;
}
float bottom() {
return y+h/2;
}
float left() {
return x-w/2;
}
float right() {
return x+w/2;
}
}
In the code below, you are setting start to true when the key is pressed and false when the press is done. You can simply remove the line that sets start to false when the key press is done and the ball will always move when the space is pressed.
//Movement
void keyPressed() {
player1.pressed((key == 'w' || key == 'W'), (key == 's' || key == 'S'));
player2.pressed((keyCode == UP), (keyCode == DOWN));
if (key == ' '){start = true;}
}
void keyReleased() {
player1.released((key == 'w' || key == 'W'), (key == 's' || key == 'S'));
player2.released((keyCode == UP), (keyCode == DOWN));
//if (key == ' ') {start = false;}
}
I suppose you want the ball to stop moving when space is pressed again. This can be done in your keyPressed method as well by toggling start instead of setting it to true. Something like if (key == ' '){start = !start;}
Your problem is that when you release the space bar, it sets the start field to false. Then when the next draw() method is called, it sees that start==false and so doesn't move the ball.
If you remove that line from the keyReleased method, then it should run correctly?
Below is my code, as I understand it, the player should be both moving and jumping while in the air, because in the draw() function, it is two if statements, not an if-else. I assume keyPressed() checks the keyboard input constantly, since holding a key will make the square move constantly. However after jumping, the character will not move at all if the key is held beginning while the cube is in a jump. Please help!
This code is literally the entire project; I plan on adding platforms in the future, and then I will go from there.
boolean newletter;
boolean direction;
boolean jump;
float velocity;
float velocityconst;
Player player;
class Player {
color c;
float xpos;
float ypos;
float xspeed;
Player(color clr, float xPos, float yPos, float xSpeed) {
c = clr;
xpos = xPos;
ypos = yPos;
xspeed = xSpeed;
}
void display() {
rectMode(CENTER);
noStroke();
fill(c);
rect(xpos,ypos,20,20);
}
void drive(boolean dir) {
if ((xpos + xspeed) > width && (dir)) {
float remainder = float(width) - xpos;
xpos = 0 + (xspeed - remainder);
} else if ((xpos - xspeed) < 0 && !(dir)) {
float remainder = xpos - 0;
xpos = width - (xspeed - remainder);
} else {
if (dir) xpos += xspeed;
else xpos -= xspeed;
}
}
void jump() {
velocity = velocity + 0.5;
if(ypos + velocity > (height/2)) {
ypos = height/2;
jump = false;
velocity = velocityconst;
} else {
ypos += velocity;
}
}
}
void setup() {
size(1000,1000);
player = new Player(color(255,0,0),0,height/2,10);
velocityconst = -8.0;
velocity = velocityconst;
}
void draw() {
background(255);
if(newletter == true) {
player.drive(direction);
}
if(jump == true) {
player.jump();
}
player.display();
newletter = false;
}
void keyPressed()
{
if((key == 'A') || (key == 'a')) {
direction = false;
newletter = true;
} else if ((key == 'D') || (key == 'd')) {
direction = true;
newletter = true;
} else {
newletter = false;
}
if ((key == 'W') || (key == 'w')) {
jump = true;
}
}
There are 2 reasons preventing, that the player is moving and jumping simultaneously.
The state which indicates the movement (newletter) is reset in every frame:
void draw() {
// [...]
newletter = false;
}
When the key which is pressed is not a or d, then the movement is stopped:
void keyPressed()
{
if((key == 'A') || (key == 'a')) {
// [...]
} else if ((key == 'D') || (key == 'd')) {
// [...]
} else {
newletter = false;
}
// [...]
}
Don't stop the movement in draw():
void draw() {
background(255);
println(newletter, " ", jump);
if(newletter == true) {
player.drive(direction);
}
if(jump == true) {
player.jump();
}
player.display();
}
and don't stop it when w (or another key) is pressed:
void keyPressed()
{
if(key == 'A' || key == 'a') {
direction = false;
newletter = true;
} else if (key == 'D' || key == 'd') {
direction = true;
newletter = true;
}
if (key == 'W' || key == 'w') {
jump = true;
}
}
But add a keyReleased() callback, to stop the movement, when a or d is released:
void keyReleased()
{
if (key == 'A' || key == 'a' || key == 'D' || key == 'd') {
newletter = false;
}
}
So I'm just making a 2d game in my spare time and I am having a hard time understanding why my collision code breaks after my character jumps but works when my character is jumping.
Relevant Code from the main class
public void collision() {
Rectangle body = jan.getBody();
int bodyX = (int) body.getX();
int bodyY = (int) body.getY();
if (bodyX < 0) {
body.setLocation(0, bodyY);
jan.setBody(body);
}
if (bodyX > 780) {
body.setLocation(780, bodyY);
jan.setBody(body);
}
if (bodyY > 360) {
body.setLocation(bodyX, 360);
jan.setBody(body);
}
}
public void actionPerformed(ActionEvent e) {
jan.update();
collision();
repaint();
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT) {
jan.setDirection(-1);
} else if (keyCode == KeyEvent.VK_RIGHT) {
jan.setDirection(1);
} else if (keyCode == KeyEvent.VK_SPACE) {
jan.jump();
}
}
Relevant code from the Player Class
public void jump() {
int y = (int) body.getY();
if (y == 360) {
body.translate(0, -15);
yVelocity = 15;
}
}
public void update() {
int x = getDirection();
if (x == 1) {
if (xVelocity < terminalVelocity) {
xVelocity++;
}
}
if (x == -1) {
if (xVelocity > -terminalVelocity) {
xVelocity--;
}
}
if (x == 0) {
if (xVelocity < 0) {
xVelocity++;
} else if (xVelocity > 0) {
xVelocity--;
}
}
if (body.y < 360) {
yVelocity--;
}
body.translate(xVelocity, -yVelocity);
}
Any reasons for why my code breaks down after my character jumps?
The logic of collision undoes the clamping in X if Y is also out of bounds. Try clamping in both x and y and then update the body if there's a change:
public void collision() {
Rectangle body = jan.getBody();
int bodyX = (int) body.getX();
int bodyY = (int) body.getY();
int clampedBodyX = Math.min(Math.max(0, bodyX), 780);
int clampedBodyY = Math.min(Math.max(0, bodyY), 360);
if (bodyX != clampedBodyX || bodyY != clampedBodyY) {
body.setLocation(clampedBodyX, clampedBodyY);
jan.setBody(body);
}
}