I have been working on a 2D game, kind of like Terraria, and i have got to the stage where i am ready to do collision detection. I tried it myself, but it... well, its very strange. I was wondering if anybody could help me with this. I store all of my blocks in a 2D array:
Block[][] map = new Block[mw][mh];
where mw is map width and mh is map height (in terms of number of blocks). Each Block is an image that is displayed as 16x16 pixels. Here is what i attempted, i know that it is wrong but i dont really know what i need to do.
private void checkCollision() {
for(int x = -1; x <= 1; x++){
for(int y = -1; y <= 2; y++){
Rectangle obj = new Rectangle((int)Block.getXOnScreen(xblock+x), (int)Block.getYOnScreen(yblock+y), 16, 16);
try{
if(main.map[(int) (xblock+x)][(int) (yblock+y)].solid && obj.intersects(bounds()){
if(y <= -1 && velY > 0){
velY = 0;
System.out.println("Collision below");
onground = true;
}else if(y >= 2 && velY < 0){
velY = 0;
System.out.println("Collision above");
}
if(x <= -1 && velX < 0){
velX = 0;
System.out.println("Collision left");
}else if(x >= 1 && velX > 0){
velX = 0;
System.out.println("Collision right");
}
}
}catch(Exception e){}
}
}
}
I call this method every tick like so, but it doesn't collide with anything so the player just falls.
public void tick(){
xblock += velX;
yblock += velY;
velY += gravity;
checkCollision();
}
If anyone knows how to do collision detection efficiently please can you share this with me. Thanks! :)
Based on the few JavaFX/Swing applications that I once wrote, the way you want to detect collision is by always keeping track of where the object is, and when it moves check to see that it is new location (old + movement count) is not exceeding the limits of the map. If it does, you want to reset its position to be right on limit so that it can go in all other directions that are valid. If you keep trying to move outside of the limits then it should keep resetting your position.
So say the limit of the page is 500 pixels wide, you are in position 495, and each move is 10, next time you move you would in position 505, so that's clearly out of range. Thus you run a check if(currentPosition > limit) {reset position to limit} thus your currentPosition will be set to 500 which is right on the border, and within the limits.
Related
I made an animation where a lot of lines (water drops) fall; by clicking with the left mouse, you just slow them down. What I also want to do is controlling their Y value as thei fall: when I click with my right mouse, they will all follow it.
Drop[] drops = new Drop[270]; // array
void setup() {
size(640, 360); // size of the window
for (int i = 0; i < drops.length; i++) {
drops[i] = new Drop();
}
}
void draw() {
background(52);
for (int i = 0; i < drops.length; i++) {
drops[i].fall();
drops[i].show();
drops[i].noGravity();
}
}
And the Drop class:
class Drop {
float x = random(width); // posizione x di partenza
float y = random(-180,-100); // posizione y di partenza
float yspeed = random(2,7); // velocità random
void fall() {
y += yspeed;
if (y > height) { // riposizionamento delle gocce
y = random(-180,-100);
}
}
void noGravity(){ //
if(mousePressed && (mouseButton == LEFT)){
y -= yspeed*0.75;
}
if(mousePressed && (mouseButton == RIGHT)){
this.y = mouseY + yspeed;
}
}
void show() { // funzione per l'aspetto delle gocce
stroke(52, 82, 235);
line(x,y,x,y+20);
}
}
The function I'm talking about is noGravity(), but when I click the right mouse,intead of following my mouse, all the drops just line up. Any simple suggestions? Thank you all!!!
Changing the y position when you right click isn't the same as changing the speed at which the drops moves. You probably just didn't notice.
Here, try changing the part where you catch the right click in noGravity() for these lines:
yspeed = abs(yspeed); //this is so the drops behaves normally again when you stop right clicking
if(mousePressed && (mouseButton == RIGHT)){
if (mouseY < this.y) { //this makes the drops go toward the mouse position
yspeed = yspeed * -1; //going up is negative speed
}
}
This is kinda cool. Notice how, if you hold the right click down, when you move the mouse the drops try to follow using their own speed. I have no idea what you're doing, but I like it.
I wasn't sure about the desired result, so let me know if I misunderstood.
ive been working on this side project trying to make a battle ship game from some time now. I have come across a few things I do not know how to do. I was wondering if anyone knew how I could make each of the five ships with their appropriate lengths and then randomize their location on the boards.
I draw the two boards like this in my void setup()
//drawing grid
for(int i = 0; i < 10; i++){
for(int j = 0; j <10; j++){
squares.add(new ObjGame( 20+50*i,75+50*j));
squares.add(new ObjGame( 580+50*i,75+50*j));
}
}
here is where I create the matrix for the ships and the hit icons. I do it in their own class in order to try and keep my main kinda clean
ObjGame(int xi, int yi){
ship = random(5)<.5;
x = xi;
y = yi;
}
void draw(){
pushMatrix();
translate(x,y);
fill(25,200,222);
stroke(c1,c2,c3);
rect(0,0,50,50);
if(!ship && clicked){
fill(255); //white circle for miss);
ellipse(25,25,30,30);
}
else if(ship && clicked){
fill(255,0,0); //red circle for hit
ellipse(25,25,30,30);
}
else{
fill(25,200,222);
rect(0,0,50,50);
}
popMatrix();
}
void attacked(){
if(mouseX <= 500){
if(mouseX> x && mouseX< x+ 50 && mouseY > y && mouseY < y+50){
clicked = true;
println(x+" "+y);
}
}
i am also trying to print out their coordinates but I want them to print out 0 - 9 instead of their actual x and y coordinates, is there an easy way to fix that or should I just be switching them?
I have been stuck on making some collision detection in my game (its kind of like Terraria) for a while but i made this code and... well, it kind of works. It works if the collision is above or on the left of the player, but if the collision is on the right, or below, instead of bouncing back, the player accelerates through the blocks until there is empty space. Here is the code that i made:
private void checkCollision() {
for(int x = (int) (xpos-1); x <= xpos+1; x++){
if(x < 0 || x > main.mw-1) continue;
for(int y = (int) (ypos-2); y <= ypos+1; y++){
if(y < 0 || y > main.mh-1) continue;
if(main.map[x][y] == null) continue;
if(!main.map[x][y].solid) continue;
if(main.map[x][y].blocktype == -1) continue;
double distance = Math.sqrt((xpos-x)*(xpos-x) + (ypos-y)*(ypos-y));
if(distance > 1.0){
continue;
}else{
double x_overlap = Math.max(0, Math.min(xpos + 16, x + 16) - Math.max(xpos, x));
double y_overlap = Math.max(0, Math.min(ypos + 32, y + 16) - Math.max(ypos, y));
double overlapArea = x_overlap * y_overlap;
if(overlapArea > 0){
if(x_overlap > y_overlap){
yblock += y_overlap/2;
}
if(x_overlap < y_overlap){
xblock += x_overlap/2;
}
//guessing i need to do something here to make player
go other way if block is on other side
}
}
}
}
}
So how would i make the player bounce back if the block that he is colliding with is on the right or below. Also is there any way i can make this smoother - right now the player be bouncing all over the place. Thanks! :)
What you want to do is keep track of the player's location, and if the location after moving is out of bounds you can reset the player's position to be right on the edge of the limit.
That's how I dealt with collision detection, I answered another question similar to this one though some folk decided to downvote the answer, go figure.
I'm following a course in programming in the Java-based environment "Processing". One assignment is to write a program that displays 3 buttons (black). When the button is clicked, that button should change to another colour (grey). We are required to use a boolean[] array. My code is as follows:
boolean[] button = new boolean[3];
void setup(){
size(300,300);
button[0] = false;
button[1] = false;
button[2] = false;
}
void draw(){
int x = (width/(button.length+1));
int y = height/2;
int ellipseSize = 50;
int radius = ellipseSize/2;
background(255);
noStroke();
fill(0);
for(int i = 1; i <= button.length; i++){
ellipse(i*x, y, ellipseSize, ellipseSize);
}
}
//shifting array values upon mouse pressing
void mousePressed(){
int x = (width/(button.length+1));
int y = height/2;
int ellipseSize = 50;
int radius = ellipseSize/2;
for(int i = 1; i <= button.length; i++){
button[i] = !button[i];
if (mouseX > i*x-radius && mouseX < i*x+radius && mouseY > y-radius && mouseY < y+radius){
if (button[i]){
fill(150);
}
}
else {
fill(0);
}
ellipse(i*x, y, ellipseSize, ellipseSize);
}
}
I get an error saying "ArrayIndexOutOfBoundsException: 3". Can someone help?
You get the error ArrayIndexOutOfBoundsException: 3 because you have tried to access to an illegal index. In Java and in most programming languages arrays start at 0.
So, in your for loop you need to change i <= button.length to i < button.length
As few people mentioned arrays in most programming languages start at index 0 and last index is at button.length - 1 so you need to change for loop or button[i] call.
But to finish your buttons you will need to understand more about processing. Your draw function is called repeatedly (depending on you fps) and you always clear the sketch with background function. Then you set fill color to black and draw three circles. If you change fill inside mouse event it might sometimes work (if you click at the same moment as circle is drawn) but it is very bad approach.
You will need to set fill according to your button array within draw function:
for(int i = 1; i <= button.length; i++){ //good boundaries for drawing but not for array
if(button[i-1]) { //for array you need correct index
fill(0);
}else{
fill(150);
}
ellipse(i*x, y, ellipseSize, ellipseSize);
}
And of course change the mouse event to just check if button was clicked and store this information inside button array for next drwing.
for(int i = 1; i <= button.length; i++){ //your old boundaries
if (mouseX > i*x-radius && mouseX < i*x+radius && mouseY > y-radius && mouseY < y+radius){
button[i-1] = !button[i-1]; //updated index
}
}
Change
i <= button.length
to
i < button.length
If the length of the array is 3 then button[2] is the last element.
I am struggling with what must be a basic concept, but can you have a look at my issue?
I have the code where: ai moves the player bat, HEIGHT = total height of Display, and batHeight is the size of the pong paddle/bat:
public void ai(int bally, int HEIGHT, int batHeight) {
if (bally < this.y + ySize / 2) {
if (this.y <= 0) {
System.out.println("Upper Bound");
y = 0;
} else {
y -= 2;
}
}
if (bally > this.y + ySize / 2) {
if (this.y >= HEIGHT - batHeight) {
System.out.println("Lower Bounds");
y = HEIGHT - batHeight;
} else {
y += 2;
}
}
}
The above does exactly what I want it to do. Pong Bat moves up, and when it hits the top of the screen, it prints the console line, and stops the Bat. Exactly the same happens at the bottom of the screen. It prints the console, and stops the bat. It does this every time with no issues.
Now, if I modify the code slightly:
public void ai(int bally, int HEIGHT, int batHeight) {
if (bally < this.y + ySize / 2) {
if (this.y <= 0) {
System.out.println("Upper Bound");
y = 0;
} else {
if(rand.nextInt(2)+1 == 1){
y -= 2;
}else{
y -=3;
}
}
}
if (bally > this.y + ySize / 2) {
if (this.y >= HEIGHT - batHeight) {
System.out.println("Lower Bounds");
y = HEIGHT - batHeight;
} else {
y += 2;
}
}
}
It iterates once, stopping at the top bound, but then it loses itself, and forgets the bounds and the bat moves off the screen. I have Console printing the Bat y position, and it tracks with no issue, accurately displaying its y co-ord, but after the first iteration, it goes to negative y and greater that screen height.
I did have the theory that you cannot nest a IF inside an ELSE statement, so i tried moving it around so that it read:
if(this.y != 0){
if(rand.nextInt(2) + 1 == 1){
//move the paddle at speed 1
} else {
//move paddle at speed 2
}
}else{
//do not move the paddle
}
But that made no difference.
The idea behind the code was to add some chance for the AI bat. Sometimes its fast, and other times it is slower.
Thanks in advance,
Your code from far away looks like this:
for a given time:
if the ball is below the paddle {
if the paddle is below the screen, put it back
else move it down 2 or 3 units
}
if the ball is above the paddle {
if the paddle is above the screen, put it back
else move it up 2 units
}
Imagine the case where the ball is at y = 1 and the paddle is at y = 2. The first if statement will be triggered (1 < 2), the paddle is not outside (2 > 0), so it moves down 2 or 3 units. Let's say 3, for argument's sake. Now, paddle is at y = -1, the ball is still at y = 1. Now, the condition for the second big if is true! So we enter it: the paddle's not above, and we move it up two units. Now, the paddle is at y = 1...
It is clear that it should not have entered the second loop. So, stick an else in front of it, because it should only ever enter one :)