I have finally gotten collision detection working by using intersects() between 2 rectangles, and it seems to be working. However the player is just getting stuck in the rectangle and can't move. So I am now trying to check collision before the player moves.
Here is what I have tried:
if(up == true){
Rectangle futurerect = new Rectangle(px,py-=5,81,150);
if(!futurerect.intersects(wallexample)){
py-=5;
repaint();
}
}
if(down == true){
Rectangle futurerect = new Rectangle(px,py+=5,81,150);
if(!futurerect.intersects(wallexample)){
py+=5;
repaint();
}
}
if(left == true){
Rectangle futurerect = new Rectangle(px-=5,py,81,150);
if(!futurerect.intersects(wallexample)){
px-=5;
repaint();
}
}
if(right == true){
Rectangle futurerect = new Rectangle(px+=5,py,81,150);
if(!futurerect.intersects(wallexample)){
px+=5;
repaint();
}
}
I just create a new rectangle but at where it would be if the player moved, and check if it collides. If it does, don't move.
The problem is, when the player moves into the rectangle, it just slows down. It still moves through the wall but just moves at a slower pace for some reason.
What is causing this issue?
It looks like you aren't checking the correct area because your instantiation of a new Rectangle is incrementing / decrementing the py or px and assigning it that value in the constructor of Rectangle.
So if you have a player at 0,0 in Cartesian and you want to know if they move up will they hit a wall.
if (up == true) {
Rectangle futurerect = new Rectangle(px,py-=5,81,150);
if(!futurerect.intersects(wallexample)){
py-=5;
repaint();
}
}
py is now set to -5 once you instantiate the Rectangle.
Rectangle futurerect = new Rectangle(px,py-=5,81,150);
because of py-=5 in the second parameter.
When you perform the intersect inspection it is looking at 0, -5. Once that says "Yes, no wall here" you decrement the py another 5. Now we have a player coord px, py of 0, -10 and you didn't check for a wall in that location.
Try fixing the logic here so it doesn't assign the new value to px / py:
Rectangle futureRect = new Rectangle(px, py - 5, 81, 150);
Related
im trying to make the bouncing ball bounce on the arrays of rectangles. I've looked at various other codes but cant seem to find a solution. Would appreciate any help!!!
Basically, i want the bouncing ball to recognise that theres the rectangles there and for it to be able to jump onto the rectangles.
PVector location; // Location of shape
PVector velocity; // Velocity of shape
PVector gravity; // Gravity acts at the shape's acceleration
PVector upwardForce;
PImage bg;
int radius = 10, directionX = 1, directionY = 0;
float x=20, y=20, speed=0.5;
int xarray[] = new int[20];
int yarray[] = new int[20];
// =========================================================
void setup() {
size(380,750);
location = new PVector(100,50);
velocity = new PVector(0.0,2.1);
upwardForce = new PVector(0.0,-10.0);
gravity = new PVector(0,0.4);
bg = loadImage("bg.png");
bg.resize(1600,1600);
background(0);
for(int i =0; i< 20;i++){
xarray[i]= i*100;
yarray[i] = 750-int(random(10))*50;
}
}
int xd =0, yd=0;
void draw() {
background(0);
noStroke();
xd--;
yd++;
// display image twice:
image(bg, y, 0);
image(bg, y+bg.height, 0);
// pos
y--;
if (y<-bg.height)
y=0;
for (int i = 0;i< 20;i++){
if (xarray[i] <100 && xarray[i]+100 >100){
fill(255,0,0);
}
else {
fill(255);
}
rect(xarray[i],yarray[i],100,1200);
fill(255);
xarray[i]=xarray[i]-4;
//yarray[i]=yarray[i]+1;
if (xarray[i] + 100 < 0){
xarray[i]+=2000;
// yarray[i]-=850;
}
}
// changing Position
x=x+speed*directionX;
y=y+speed*directionY;
// check boundaries
if ((x>width-radius) || (x<radius))
{
directionX=-directionX;
}
if ((y>height-radius) || (y<radius))
{
directionY=-directionY;
}
// draw
// if(direction==1)
// Add velocity to the location.
location.add(velocity);
// Add gravity to velocity
velocity.add(gravity);
// Bounce off edges
if ((location.x > width) || (location.x < 0)) {
velocity.x = velocity.x * -1;
}
if ((location.y > height) || (location.y < 0)){
// We're reducing velocity ever so slightly
// when it hits the bottom of the window
velocity.y = velocity.y * -0.95;
location.y = height;
}
// Display circle at location vector
stroke(255);
strokeWeight(0);
fill(255);
ellipse(location.x,location.y,30,30);
}
void keyPressed()
{
velocity.add(upwardForce);
}
The best advice we can give you is to break your problem down into smaller steps and to take those steps on one at a time.
For example, can you create a simple sketch that just shows a single hard-coded circle and a single hard-coded rectangle? Now add some code that prints a message to the console if they're colliding. You're going to have to do some research into collision detection, but here's a hint: a common technique is to treat the ball as a rectangle, so you can do rectangle-rectangle collision detection.
Get that working perfectly by itself, and then work your way forward in small steps. Can you add a second rectangle to your sketch? How about a third?
Then if you get stuck, you can post a MCVE (not your whole project, just a small example) along with a more specific question. Good luck.
Here's a few suggestions:
You're best off using a Rectangle class. That way, you don't have to store the locations in an array, and the collide function can be a method of the class. It's easier to just call the positions of the rectangles "x" and "y", but this would obviously conflict with the x and y global variables which you declared at the top of the code. Assuming that you would want to make the ball bounce if it collided, you would need to have a "ballLastx" and a "ballLasty" in order to keep track of which direction the ball came from. You would also need to store the Rectangles in an array or arrayList. It would be something like this:
PVector lastLocation;
Rectangle[] rects;
As for the rectangle class, here's how it would probably look like this:
class Rectangle {
float x, y;
Rectangle(float x_, float y_) {
x = x_;
y = y_;
}
void show() {
//Displays rectangle
if (x < 100 && x+100 > 100) fill(255,0,0);
else fill(255);
rect(x,y,100,1200);
fill(255);
x=x-4;
if (x + 100 < 0) x+=2000;
}
private boolean insideX(PVector pos) {
return (pos.x + 15 >= x && pos.x - 15 <= x+100);
}
private boolean insideY(PVector pos) {
return (pos.y + 15 >= y && pos.y - 15 <= x + 1200);
}
boolean collidedX() {
//Detects if the ball has collided along the x-axis
return ((insideX(location) && !insideX(lastLocation)) && insideY(location))
}
boolean collidedY() {
//Detects if the ball has collided along the y-axis
return ((insideY(location) && !insideY(lastLocation)) && insideX(location))
}
}
And then, in your setup function, you could declare the Rectangle classes in a for-loop:
//declare the rects array
rects = new Rectangle[20];
//declare each item of the rects array to be a Rectangle
for(int i = 0; i < rects.length; i++) {
rects[i] = new Rectangle(i*100, 750-int(random(0,10))*50;
}
In order to detect the collision and to bounce the ball, you would need to loop through all of the Rectangles and see if the ball should bounce off any of them:
boolean bouncex = false;
boolean bouncey = false;
//see if any of the rects are colliding with the ball
for(Rectangle r : rects) {
if(r.collidedX()) bouncex = true;
if(r.collidedY()) bouncey = true;
}
//if any are colliding, bounce the ball
if(bouncex) velocity.x = -velocity.x;
if(bouncey) velocity.y = -velocity.y;
Finally, don't forget to set the lastLocation PVector to the current location, just before moving the current location:
lastLocation = location.copy();
//move the ball...
Hope this was helpful!
I am trying to get a ball to bounce off a square, but I am having trouble detecting the collision and having the ball bounce properly.I tried making two rectangles and using intersect, but this doesn't work and I don't know why. Should I write the collision detection manually? If so, how? Or is the rectangle method not working because of some other issue in my project. Here is my current collision detection.
public boolean collidedWith(Ball ball){
int ballX = ball.getXPosition();
int ballY = ball.getYPosition();
int ballRadius = ball.getRadius();
int squareX = this.getXPosition();
int squareY = this.getYPosition();
Rectangle me = new Rectangle(squareX, squareY, size, size);
Rectangle other = new Rectangle(ballX, ballY, ballRadius,ballRadius);
if(me.intersects(other)|| other.intersects(me))
{
return true;
}
else
return false;
}
}
I find it very hard to understand your code. You didn't quite well.
But in order to detect a collision -
You check if the ball hit the bounds of the square.
if (Math.abs(ballX + ballVelocityX) + ballRadius > SquareX)
...;
if (Math.abs(ballY + ballVelocityY) + ballRadius > SquareY)
...;
Math abs is the absolute value.
made two circles one of radius 8(image 16x16)
and one of radius 20( image 40x40)
i am calling the circle over overlap method and the collsion is just off. It is colliding with a circle that is around the 0,0 point of where ever my image of the ball is. the bullet can go within the ball on the bottom and right sides.
public class MyGame extends ApplicationAdapter {
SpriteBatch batch;
Texture ballImage, bulletImage;
OrthographicCamera cam;
Circle ball;
Array <Circle> bullets;
long lastShot;
#Override
public void create ()
{
System.out.println("game created");
ballImage = new Texture(Gdx.files.internal("ball.png"));
bulletImage = new Texture(Gdx.files.internal("bullet.png"));
cam = new OrthographicCamera();
cam.setToOrtho(true,320,480);//true starts top right false starts top left
batch = new SpriteBatch();
ball = new Circle();
ball.radius=20;
ball.x=320/2-ball.radius; // half screen size - half image
ball.y=480/2-ball.radius;
bullets = new Array<Circle>();
spawnBullet();
/*
batch.draw(bulletImage,bullet.x,bullet.y);
bullet.x++;
bullet.y++; */
}
public void spawnBullet()
{
Circle bullet = new Circle();
bullet.radius=8;
bullet.x=0;
bullet.y=0;
bullets.add(bullet);
lastShot = TimeUtils.nanoTime();
}
#Override
public void render ()
{
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
batch.draw(ballImage,ball.x,ball.y);
for(Circle bullet: bullets)
{
batch.draw(bulletImage, bullet.x, bullet.y);
}
batch.end();
if(Gdx.input.isTouched())
{
Vector3 pos = new Vector3();
pos.set(Gdx.input.getX(), Gdx.input.getY(),0);
cam.unproject(pos);
ball.y = pos.y - ball.radius;
ball.x = pos.x - ball.radius ;
}
//if(TimeUtils.nanoTime()-lastShot >1000000000) one second
//spawnBullet();
Iterator<Circle> i = bullets.iterator();
while(i.hasNext())
{
Circle bullet = i.next();
bullet.x++;
bullet.y++;
if(bullet.overlaps(ball))
{
System.out.println("overlap");
i.remove();
}
}
}
}
If your bullet and the ball are 2 circles, like you said you don't need an overlap method.
It is simple: 2 circles collide, if their distance is smaller then the sum of their radiuses.
To calculate the distance you need to make a squareroot. This is a pretty expensive calculation, so it would be better to use squared distance and squared sum of radiuses:
float xD = ball.x - bullet.x; // delta x
float yD = ball.y - bullet.y; // delta y
float sqDist = xD * xD + yD * yD; // square distance
boolean collision = sqDist <= (ball.radius+bullet.radius) * (ball.radius+bullet.radius);
Thats it.
Also in your cam.setToOrtho you wrote a cooment:
//true starts top right false starts top left
Thats wrong, it is top left or bottom left. By default it is bottom left, because this is the way a coordinate system works normaly. The top left is, because the monitor addresses pixels starting from top left = pixel 1.
EDIT: this should be the problem: The coordinates you give the batch.draw method are the left lower corner of the Texture by default, if you are using the "y = Down"-System it should be the top left corner (you have to try i am not sure).
The Circles position instead is its center.
To solve the problem you need to adjust the position like this (for "y = Up"-System):
batch.draw(bulletImage, bullet.x - bullet.radius, bullet.y - bullet.radius);
It is possible, that the same formula works also for the "y = Down"-System but i am not sure
So I'm working on a collision detection code and what i do is when the user rectangle overlaps the rectangle where they cant move, I stop them from moving. So if im moving right and I hit a wall i cant move forward. This works. However if after i hit that wall, I want to move down or up form that point, I get stuck.
This is how i check if the user has colidded
private void checkCollision() {
for (int x = 0; x < amount; x++) {
if (collsionRect[x].overlaps(user)) {
Gdx.app.log(ChromeGame.LOG, "Overlap");
xD = 0;
yD = 0;
}
}
}
And this is how I move my user
private void moveUser() {
// camera.translate(xD, yD);
player.translate(xD, yD);
camera.position.set(player.getX(), player.getY(), 0);
// Gdx.app.log(ChromeGame.LOG, player.getX() + "," + player.getY());
user = new Rectangle(player.getX(), player.getY(), player.getWidth(),
player.getHeight());
checkCollision();
}
In my render method I keep calling the move userMove method till I let go of the keyboard wher eit turns the xD,yD to zero
The problem is that you check if rectangles overlap. This means that your character is not colliding unless some part of him is already inside the wall, then he stops moving. The next time you want to move the character he is already colliding (a part of him is inside the wall) and so checkCollision() will set xD, yD to 0 and your character won't move.
The easiest solution to this is to make a "fake" move (interpolation) and check if this new move will make him collide, if he will collide you simply don't accept this new move. In pseudocode
new position = player.x + deltaX, player.y+deltaY
create new rectangle for player from new position
check collision with new rectangle
if not collide player.x += deltaX, player.y+=deltaY
I'm trying to implement a simple pong game. I want the ball to change X direction or Y direction depending what side of the ball was hit.
The ball moves at 3 pixels per second and has a width of 22 and height of 22. The paddles have a width and height of 32.
For collision detection on the ball, should I just create one rectangle and check for collision with the center point?
Alternatively I could create 4 rectangles around the ball to represent the sides, with an appropriate width, given that the ball moves at 3 pixels per frame.
Another option is to create a method that will check for collision at least 2 pixels in the direction of motion of the ball.
If the ball is moving to the right, and the x-position is 16, the next frame will be 19.
Should I create a method that will check x for 16, 17 and 18, to make sure if there is a collision it will hit the right side and not cause the ball to actually go inside the cube?
#Sig
I now have this as my collision detection
if(Rect.intersects(balls.get(j).ball, levelBlocks.blocks.get(i).rect))
{
//Bottom
if(balls.get(j).yPos <= levelBlocks.blocks.get(i).yPos - (32/2))
{
balls.get(j).ySpeed = balls.get(j).ySpeed * -1;
}
//Top
if(balls.get(j).yPos >= levelBlocks.blocks.get(i).yPos + (32/2))
{
balls.get(j).ySpeed = balls.get(j).ySpeed * -1;
}
//Left
if(balls.get(j).xPos < levelBlocks.blocks.get(i).xPos)
{
balls.get(j).xSpeed = balls.get(j).xSpeed * -1;
}
//Right
if(balls.get(j).xPos > levelBlocks.blocks.get(i).xPos)
{
balls.get(j).xSpeed = balls.get(j).xSpeed * -1;
}
This works, but not 100%, it still seems abit off. if the ball hits two blocks at the same time, it will invert the invert so the direction will go back again.
I then changed it to this
if(Rect.intersects(balls.get(j).ball, levelBlocks.blocks.get(i).rect))
{
//Bottom
if(balls.get(j).yPos <= levelBlocks.blocks.get(i).yPos - (32/2))
{
collision = 2;
}
//Top
if(balls.get(j).yPos >= levelBlocks.blocks.get(i).yPos + (32/2))
{
collision = 2;
}
//Left
if(balls.get(j).xPos <= levelBlocks.blocks.get(i).xPos + (32/2))
{
collision = 1;
}
//Right
if(balls.get(j).xPos >= levelBlocks.blocks.get(i).xPos + (32/2))
{
collision = 1;
}
temp = levelBlocks.blocks.get(i);
levelBlocks.blocks.remove(i);
combo.blocksDestroied += 1;
Assets.score += 10 * combo.comboMultiplier;
}
}
if(collision == 1)
{
balls.get(j).xSpeed = balls.get(j).xSpeed * -1;
collision = 0;
}
if(collision == 2)
{
balls.get(j).ySpeed = balls.get(j).ySpeed * -1;
collision = 0;
}
This does work, but every now and then the ball will just start randomly going through blocks, it is very odd to look at, really confused on why it is doing it, but I do feel it is because of the 3 pixels per frame
Because the shapes you're working with are so simple, why not be perfect? Use a rectangle for the paddles and a circle for the ball when performing hit detection. Start by checking for collisions on a frame-by-frame basis; at the speeds you're working with, you shouldn't need to "look into the future" for future collisions.