I have been making a brick breaker game for fun, but I came across an odd error in the execution of the program. When the game is started, the ball is set in motion away from the bricks. However, it starts destroying them almost immediately, starting from the brick furthest to the right on the upper row and continuing to break them all from right to left. Then it goes to the second row and destroys them from left to right. This whole time, on the screen, the ball is away from any bricks.
I think I pinpointed the problem to the following piece of code. Here I create a rectangle around the ball and a rectangle around the brick and if they were to intersect, I call the method setBrickValue inside another class called Map Generator, which sets the value of the brick to 0, meaning, it doesn't exist.
Here's the method:
public void actionPerformed(ActionEvent arg0) {
timer.start();
//makes sure the ball collides with the paddle
if(play){
if( new Rectangle( ballPositionX, ballPositionY, 20, 20)
.intersects( new Rectangle( player, 550, 100, 8 ) ) ){
ballDirY = - ballDirY;
}
// beginning of the code with an error in it, the rectangle around the ball
//is intersecting incorrectly the rectangle of the brick
A:for(int i = 0; i < MGobj.map.length; i++){
for(int j = 0; j < MGobj.map[0].length; j++){
if(MGobj.map [i] [j] > 0){
int brickX = i * MGobj.brickWidth + 80;
int brickY = j * MGobj.brickHeight + 50;
int brickWidth = MGobj.brickWidth;
int brickHeight = MGobj.brickHeight;
//create the rectangle around the brick
Rectangle rect = new Rectangle( brickX, brickY,
brickWidth, brickHeight );
//create the rectangle around the ball, so we can detect the intersection
Rectangle ballRect = new Rectangle( ballPositionX, ballPositionY, 20, 20 );
Rectangle brickRect = rect;
//when intersecting, delete the brick off the map
if( ballRect.intersects( brickRect )){
MGobj.setBrickValue( 0, i, j );
totalBricks--;
score += 5;
//
if( ballPositionX + 19 >= brickRect.x ||
ballPositionX + 1 <= brickRect.x + brickRect.width ){
ballDirX = - ballDirX;
}else{
ballDirY = - ballDirY;
}
//creates a label that says when this code executes, get out of the
//outer loop
break A;
}
}
}
}
//end of the code with an error in it
//makes sure the ball is moving
ballPositionX += ballDirX;
ballPositionY += ballDirY;
//makes sure the ball isn't going beyond the borders
if(ballPositionX < 0){
ballDirX = -ballDirX;
}
if(ballPositionY < 0){
ballDirY = -ballDirY;
}
//think this code doesn't work
if(ballPositionX > 670){
ballDirX = -ballDirX;
}
}
repaint();
}
Here's the setBrickValue method:
public void setBrickValue(int value, int row, int col){
map [row] [col] = value;
}
All help is appreciated. Thank you in advance.
PS: If anybody would like to see the whole code (400ish lines), just tell me and I would upload it.
Related
I'm a beginner in coding and creating a castle defender game.
I'm trying to add bullet shooting to my code but I'm having a hard time implementing it to my project.
Here is the code I came up with for shooting the bullets downwards in the void draw() function
float bulletY = DefenderY; //bullet being set in player x position
float bulletX= DefenderX; //bullet set in player y position
rect(bulletX, bulletY, 8, 8); //creating the bullet
text("score: ", countA, 20, 80); //score counter not implemented yet
if (keyPressed && key==CODED && key == 's')// if the space bar is pressed //key press detection,
{
dropping = true; //boolean is now true when previously false
}
if(dropping == true){ if (bulletY<=400) // checking if the bullet is still within the frame
bulletY= bulletY + 1;} //boolean true then the rectangle should move from the player position
}
if(bulletY>=400){dropping = false; //when bullet hits game borders reset to player position
bulletY=DefenderY;
bulletX=DefenderX;}
However the rectangle bullet is not moving from the (DefenderY, DefenderY) position, it stays attached the the player, any help would be appreciated.
I will also post the whole code below if that helps with my question thanks.
class attackers{
float max = 400;
float min = 1;
float posx = (int)Math.floor(Math.random()*(max-min+1)+min);
float posy = 400;
float speed = 1;
}
attackers one, two, three, four;
float DefenderX= 100;
float DefenderY=100;
void setup()
{
one = new attackers();
two = new attackers();
three = new attackers();
four = new attackers();
size(400,400); //fairly large relative to objects
rectMode(CENTER); //set rect x,y to be the centre.
}
float gunX=40;
boolean dropping = false;
int countA = 0;
void draw()
{
background(#0000FF); //clear background
ellipse(DefenderX,DefenderY,20,20);//Draw player current position (x,y)
if ( abs(DefenderX - one.posx)<20 && abs(DefenderY-one.posy )<20 ||
abs(DefenderX - two.posx)<20 && abs(DefenderY-two.posy )<20 ||
abs(DefenderX - three.posx)<20 && abs(DefenderY-three.posy )<20 ||
abs(DefenderX - four.posx)<20 && abs(DefenderY-four.posy )<20
)//are they close together?
{
print ("GAMEOVER!");
}
float bulletY = DefenderY;
float bulletX= DefenderX;
rect(bulletX, bulletY, 8, 8);
text("score: ", countA, 20, 80);
if (keyPressed && key==CODED && key == 's')// if the space bar is pressed
{
dropping = true;
print("its working");
if (bulletY<=400)
bulletY= bulletY + 1;
}
if(dropping == true){
}
if(bulletY>=400){dropping = false;
bulletY=DefenderY;
bulletX=DefenderX +30;}
int randomattack, randomattack1, randomattack2, randomattack3;
randomattack = (int)Math.floor(Math.random()*(two.max-two.min+1)+two.min);
ellipse(one.posx,one.posy, 10,10); //draw ball at current position : x, y fixed at 125!
one.posy = one.posy - 1;
if (abs(one.posy -1 )<1 )
{one.posy = one.posy+ 400;
one.posx = randomattack;}
randomattack1 = (int)Math.floor(Math.random()*(two.max-two.min+1)+two.min);
ellipse(two.posx,two.posy, 10,10); //draw ball at current position : x, y fixed at 125!
two.posy = two.posy - 1;
if (abs(two.posy -1 )<1 )
{two.posy = two.posy+ 400;
two.posx = randomattack1;}
randomattack2 = (int)Math.floor(Math.random()*(two.max-two.min+1)+two.min);
ellipse(three.posx,three.posy, 10,10); //draw ball at current position : x, y fixed at 125!
three.posy = three.posy - 1;
if (abs(three.posy -1 )<1 )
{three.posy = three.posy+ 400;
three.posx = randomattack2;}
randomattack3 = (int)Math.floor(Math.random()*(one.max-one.min+1)+one.min);
ellipse(four.posx,four.posy, 10,10); //draw ball at current position : x, y fixed at 125!
four.posy = four.posy - 1;
if (abs(four.posy -1 )<1 )
{four.posy = four.posy+ 400;
four.posx = randomattack3;}
}void keyPressed()
{
if (key==CODED)
{
if (keyCode == LEFT)
{ DefenderX = DefenderX - 5; }
if (keyCode == RIGHT)
{ DefenderX = DefenderX + 5; }
}
}
This is the part of your code that draws the bullet:
float bulletY = DefenderY;
float bulletX = DefenderX;
rect(bulletX, bulletY, 8, 8);
You set the bullet position to Defender position and then immediately draw it.
You have some code later on that adjusts the bullet position, but it won't have any effect because you've already drawn the bullet on screen at the original position.
Also note that the draw function runs every frame, so you probably don't want to be resetting the bullet position each frame like that or it will be difficult to get it to move anywhere. Declare the variables for bullet position outside of draw and only reset them when the bullet is initially fired.
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!
This is a follow-up post to my previous question, here. I got a remarkable response to instead of using array data tracking, to use matrixes. Now, the code here works just as planned (as in, the rectangles somewhat most of the time get filled in properly with white), but it's very inconsistent. When holding the left or right mouse button the colors phase over each other in a battle of randomness, and I don't know nearly that much about why this is happening. Just for reference, I'm using Java in Processing 3.
This is a result that I made with the project. As you can see, it looks fine.
Except for that jitter when hovering over a rect, and that more than not the rectangles are not being filled in half the time. And plus, the hover color is cycling almost randomly.
int cols, rows;
int scl = 20;
boolean[][] matrix = new boolean[scl+1][scl+1];
void setup() {
size(400, 400);
int w = 400;
int h = 400;
cols = w / scl;
rows = h / scl;
}
void draw() {
background(255);
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
int xpos = x*scl;
int ypos = y*scl;
stroke(55);
if ((mouseX >= xpos && mouseX <= xpos+scl) &&
(mouseY >= ypos && mouseY <= ypos+scl)) {
fill(75);
if (mousePressed == true) {
println("Clicked at: " + xpos + " and " + ypos);
if (!matrix[xpos/scl][ypos/scl]) {
matrix[xpos/scl][ypos/scl] = true;
} else {
matrix[xpos/scl][ypos/scl] = false;
}
fill(100);
//here is the desired location for the fill to remain constant even
//after unclicking and leaving hover
}
println("Mouse at: " + xpos + " and " + ypos);
} else {
fill(50);
}
if (matrix[x][y]) {
//fill(204, 102, 0);
fill(240);
rect(xpos, ypos, scl, scl);
}
rect(xpos, ypos, scl, scl);
}
}
}
Remeber that Processing fires the draw() function 60 times per second.
So your check for whether the mouse is pressed is happening 60 times per second. That means you're toggling the state of whatever cell the mouse is in 60 times per second.
To fix that problem, you might switch to using the event functions like mousePressed() instead of constantly polling every frame.
From the reference:
int value = 0;
void draw() {
fill(value);
rect(25, 25, 50, 50);
}
void mousePressed() {
if (value == 0) {
value = 255;
} else {
value = 0;
}
}
As for certain cells being skipped over, that's because when you move the mouse, it doesn't actually go through every pixel. It "jumps" from frame to frame. Those jumps are usually small enough that humans don't notice it, but they're large enough that it's skipping over cells.
One solution to this is to use the pmouseX and pmouseY variables to calculate a line from the previous mouse position to the current mouse position, and fill in any cells that would have been hit along the way.
So the title pretty much explains it all, recently I have learned about 2D arrays but I am a little confused on how to make the 2D array move correctly in this Space Invaders game I am creating.
Right now I have Aliens moving left to right (and vice versa), however, they don't all move down at the same time, they move down column by column. Anyone know where to edit the code?
Here is my code for the Aliens:
class Aliens {
int x = 100, y = 75, deltaX = 1;
Aliens (int x, int y) {
this.x = x;
this.y = y;
}
void drawAlien() {
fill(255);
rect(x, y, 25, 25);
}
void moveAlien() {
x = x + deltaX;
if (x >= width) {
y = y + 20;
deltaX = - deltaX;
} else if (x <=0) {
y = y + 20;
deltaX = - deltaX;
}
}
void updateAlien() {
drawAlien();
moveAlien();
}
}
and my main class:
import ddf.minim.*;
//Global Variables
PImage splash;
PFont roboto;
Defender player;
Aliens[][] alienArray = new Aliens[15][3];
Missile missile;
int gameMode = 0;
int score = 0;
void setup() {
size(1000, 750);
rectMode(CENTER);
textAlign(CENTER, CENTER);
splash = loadImage("Splash.png");
player = new Defender();
for (int row = 0; row < 15; row++) {
for (int column = 0; column < 3; column++) {
alienArray[row][column] = new Aliens((row + 1) * 50, (column + 1) * 50);
}
}
roboto = createFont("Roboto-Regular.ttf", 32);
textFont(roboto);
}
void draw() {
if (gameMode == 0) {
background(0);
textSize(75);
text("Space Invaders", width/2, height/8);
textSize(25);
text("Created by Ryan Simms", width/2, height/4);
textSize(45);
text("Press SPACE to Begin", width/2, height - 100);
image(splash, width/2-125, height/4 + 75);
} else if (gameMode == 1) {
background(0);
score();
player.updateDefender();
for (int row = 0; row < 10; row ++) {
for (int column = 0; column < 3; column++) {
alienArray[row][column].updateAlien();
}
}
if (missile != null) {
missile.updateMissile();
}
if (keyPressed) {
if (key == ' ') {
if (missile == null) {
missile = new Missile(player.x);
}
}
}
if (missile != null) {
if (missile.y <= 0) {
missile = null;
}
}
}
}
void score() {
textSize(20);
text("Score: " + score, 40, 15);
}
void keyPressed() {
if (key == ' ') {
gameMode = 1;
}
}
The logic flaw is in the moveAlien() method. You move the x position of an alien by a certain delta. If it is detected that the alien has passed some screen boundary (the x >= width and x <=0 checks), you invert the delta to reverse the movement of the alien, and also update the y position to have it move down.
Since the aliens are oriented in vertical columns, one column will always reach such a boundary while the others haven't yet. So that column will go down, and also begin reverting its movement. The other columns will then "catch up" later. So not only do they move down per column, the columns will also end up moving through one another.
You'll have to implement some logic to have your aliens move as a block, by detecting when the rightmost remaining alien has reached the right boundary, or the leftmost remaining alien has reached the left boundary, and then doing an update on all aliens to move down.
The idea of having each alien have its own state, putting the logic for controlling it in the alien class and calling that is actually good object-oriented design. It just so happens that for Space Invaders, the aliens all affect one another because they move in a block. As a result, your design results in them having too much individuality. Perhaps you can add some class that maintains state for the invader array as a whole (such as the leftmost and rightmost column still having an alien, direction of the entire block), control that in your movement loop and have it update the alien's location in turn.
So i've made a simple program that have as its objective to draw a rect on the screen when a button is clicked on the mouse, if its the left button it make a rect on the left half of the screen, and if it the right it make a rect in the right half of the screen.
The problem is that i used a for loop to make the rect get drew for some time continuously, but it just does not happen.
Here is my code:
int bab = 0;
void setup() {
size(500, 500);
frameRate(24);
background(255);
int b = 0;
}
void draw() {
background(255);
println(bab);
bab++;
if(mousePressed == true && mouseButton == LEFT) {
fill(100, 0, 0);
for(int i = 0; i <= 20000; i++) {
fill(100, 0, 0);
rect(0, 200, width/2, 50);
println("The value is: " + i);
}
background(255);
}else if(mousePressed == true && mouseButton == RIGHT) {
fill(255, 255, 0);
for(int i = 0; i <= 200; i++) {
rect(width/2, 0, width/2, height);
}
}
}
Try this code:
long leftOn = 0;
long rightOn = 0;
void draw() {
// clear window buffer (white color)
background(255);
if (mousePressed == true && mouseButton == LEFT) {
// remember timestamp when left button was pressed in variable leftOn
leftOn = millis();
rightOn = 0;
} else if (mousePressed == true && mouseButton == RIGHT) {
// remember timestamp when right button was pressed
rightOn = millis();
leftOn = 0;
}
// now is current timestamp
long now = millis();
/*
* if now - last left click distance is lower than 1000 ms - draw left rect
* else if now - right left click distance is lower than 1000 ms - draw right rect
*/
if (now - leftOn <= 1000*1) {
fill(0,255,0);
rect(0,0,width/2,height);
} else if (now - rightOn <= 1000*1) {
fill(255,255,0);
rect(width/2, 0, width/2, height);
}
// else - nothing is drawn in this frame, so window will be empty in this frame
}
Looping is done by Processing - I mean when you set frame rate to 20 it means that Processing will call method draw() every 50 ms (20 times in 1 second).
So, you have to implement how 1 single frame should be drawn. You dont need looping to make things last longer.
In above code left rect will appear and last for 1 second from last left button was pressed. And right rect for 1 second from right button.
The millis() method returns the number of milliseconds that elapsed from startup. You can then remember in leftOn when left button was pressed. And you draw left rect if time difference between now and last leftOn is less then 1000 ms - for example.
Your for loop uses i as it's control / to represent each iteration through the loop. You also have the drawing happening in this loop, so that each iteration should draw something.
However, nowhere in your loop do you use the i variable -- you only print it to the console.
for(int i = 0; i <= 20000; i++) {
fill(100, 0, 0); // does not use i
rect(0, 200, width/2, 50); // does not use i
println("O valor é: " + i);
}
So what you have really is a loop that draws the exact same thing, 20000 times. So to you it looks like nothing is happening, but it is, it's just the same thing is happening repeatedly.
Maybe you wanted something more like:
for(int i = 0; i <= 20000; i++) {
fill(100, 0 + i, 0 + i);
rect(0 + i, 200, width/2, 50 + i);
println("O valor é: " + i);
}
^ I really have no idea if that makese sense... But you need to use the loop control variable i somewhere in your drawing code, or else yes, you will draw the same thing repeatedly.