I want to have the panda (which the user moves with left and right arrow keys) collide with a candy image which is falling from the top left of the screen. When the 2 images collide, it would say "YOU TOUCHED THE CANDY" on the screen and the console. But when the panda and candy touch, nothing happens.
Here is the code:
PImage candy, panda;
int pandaX = 800;
int pandaY = 790;
int candySpeed = 20;
int yDirCandy = 1;
int yPosCandy = 10;
int xPosCandy = 20;
void setup() {
candy = loadImage("goodCandy1.png");
panda = loadImage("panda.png");
}
void loadStuff() {
image(panda, pandaX, pandaY, 80, 112);
text("Lives: " + lives, 1400, 70);
image(candy, xPosCandy, yPosCandy, 187, 121);
yPosCandy = yPosCandy + (candySpeed * yDirCandy);
touchCandy(pandaX, pandaY, yPosCandy, xPosCandy);
}
void keyPressed() {
if (key==CODED) {
if (keyCode==LEFT) {
pandaX = pandaX-20;
}
if (keyCode==RIGHT) {
pandaX = pandaX+20;
}
if (pandaX<=10) {
pandaX=10;
lives = lives -1;
}
if (pandaX>=1500) {
pandaX=1500;
}
}
}
void touchCandy(int xPosCandy, int yPosCandy, int pandaX, int pandaY) {
if (pandaX==xPosCandy && pandaY==yPosCandy ) {
text("YOU TOUCHED THE CANDY!", width/2, height/2);
print("YOU TOUCHED THE CANDY!");
}
}
I tried doing if (pandaX==xPosCandy && pandaY==yPosCandy) But it didn't work. I also tried doing if (pandaX>xPosCandy && pandaY<yPosCandy) but it says YOU TOUCHED THE CANDY too soon.
Any help would be appreciated, and let me know if you need more code. Thanks!
Look at this line:
if (pandaX==xPosCandy && pandaY==yPosCandy)
This will only be true if the panda and the candy are in exactly the same position. This is pretty unlikely.
Similarly, look at this line:
if (pandaX>xPosCandy && pandaY<yPosCandy)
This will only be true if the panda is to the right and above the candy, which is not what you want.
Instead, you need to check whether they're overlapping. You'd do this by checking each side, like this:
if(rectOneRight > rectTwoLeft && rectOneLeft < rectTwoRight && rectOneBottom > rectTwoTop && rectOneTop < rectTwoBottom){
//collision
}
Shameless self-promotion: I've written a tutorial on collision detection in Processing (including rectangle-rectangle collision) available here.
Related
I am trying to make a game and am almost done with the code. But I can't make my rectangle randomly fall down from my screen.
I am coding a car game that is supposed to dodge the other cars. But is not working. can someone help me?
int carx = 200;
int cary = 0;
float speedx = 0;
float speedy = 0;
float accy = 0.1;
color rod = color(255, 0, 0);
color vit = color(255);
final int START_STATE = 1;
final int PLAY_STATE = 2;
final int GAMEOVER_STATE = 3;
final int RESTART = 4;
int state = START_STATE;
void setup() {
size(400, 700);
}
void draw() {
switch (state) {
case START_STATE:
drawStart();
break;
case PLAY_STATE:
drawPlay();
break;
case GAMEOVER_STATE:
drawGameOver();
case RESTART:
drawrestart();
}
}
void init() {
carx = 200;
cary = 0;
speedx = 0;
speedy = 0;
accy = 0.1;
}
void drawStart() {
background(0);
textAlign(CENTER, CENTER);
textSize(16);
text("Click the mouse button to start the game", width / 2, height / 2);
if (mousePressed) {
state = PLAY_STATE;
}
}
void drawGameOver() {
textAlign(CENTER, CENTER);
textSize(20);
text("you have crashed your car", width / 2, height / 2);
if (mousePressed) {
state = PLAY_STATE;
init();
}
}
void drawrestart() {
textAlign(CENTER, CENTER);
textSize(15);
text("press mouse to restart", 200, 400);
if (keyPressed) {
state = RESTART;
}
}
void drawPlay() {
background(0);
if (get(carx, cary) == vit) {
speedy = -1 * speedy;
}
fill(rod);
rect(carx, cary, 50, 30);
if (get(mouseX, 600) == color(255, 0, 0)) {
state = GAMEOVER_STATE;
}
fill(#FFFFFF);
rect(mouseX, 600, 30, 50);
carx += speedx;
cary += speedy;
speedy += accy;
}
The code you have at the moment only has one rectangle fall down from the top for each 'round' of the game. I'm not sure if you wanted to have multiple blocks falling; I think that would be a good next step.
For now, here's a simple hack which will cause the block to fall from a random position each time, like you requested.
At the very start of your code, outside of the functions, place:
boolean randomise;
Then, within void init() you should add:
randomise = true;
Finally, add this section into drawPlay(), right at the start of the function:
if (randomise){
carx = int(random(width-50));
randomise = false;
}
Note that a new random x co-ordinate will only generate every time you set the boolean 'randomise' to true again. So if you generate a new iteration with more than one block falling inside the drawPlay() function, you should bear this in mind and adjust the code accordingly.
------- [EDIT] -------
Hi, glad that this helped.
I've actually noticed another little issue which I will help you fix.
Currently, you are checking at mouseX to see whether there has been a collision. This works (mostly), but if the right side of the player's white car drives through the left edge of a red falling block, then the game continues as though nothing has happened. What should occur is that the game is over because a collision is detected. You want to find out if any part of the two shapes have overlapped.
To do this, you should alter the code like so. In drawPlay(), replace:
if (get(mouseX, 600) == color(255, 0, 0)) {
state = GAMEOVER_STATE;
}
with:
if (get(mouseX, 600) == color(255, 0, 0) || get(mouseX + 30, 600) == color(255, 0, 0)) {
state = GAMEOVER_STATE;
}
This is an OR statement - checking whether either side of the player's car has collided. This way, every time they bump into each other, the game will end.
Now for your question: how to add multiple cars?
There are a few ways you could go about this, but I'll show you the most straightforward.
In drawPlay(), you want to add this little if statement:
if (cary > height){
init();
}
Basically what we're doing here is checking if the previous red block/car has fallen off the bottom of the sketch. If it has, i.e. if the red block's y co-ordinate is larger than the height of the whole sketch, we call init() again. This will reset everything, including making randomise true. Once randomise is true, the previous code you added will select a random start point for the block, and it will fall all over again.
I hope you've understood everything I explained - whilst my code will fix your problem, the best way to learn is to try to solve things by yourself. Check out Dan Shiffman's videos on YouTube. These are a great starting place to get to grips with Processing - hopefully you'll be more confident writing your own code after following along with his examples :)
Use random to generate a random x coordinate:
carx = (int)random(0, width-50);
Reset the position and the speed of the care, once the car reached to bottom of the window:
void drawPlay() {
if (cary > height) {
carx = (int)random(0, width-50);
cary = 0;
speedy = 0;
}
// [...]
so I have this code, I'm trying to learn Java and this is basically my first game, it's similar to SubmarineKiller where you are a boat, launching bombs at the submarine.
My class below is the bomb. When I press the Down arrow, the bomb launches but I can't launch another one until it hits the submarine or it goes out of screen. My question is: How can I fire the next bomb as soon as the first one left the boat? Basically launch a bomb anytime I press my down key.
public void keyPressed(KeyEvent evt) {
int code = evt.getKeyCode();
if (code == KeyEvent.VK_DOWN) {
if (bomb.isFalling == false)
bomb.isFalling = true;
}
}
-
private class Bomb {
int centerX, centerY;
boolean isFalling;
Bomb() {
isFalling = false;
}
void updateForNewFrame() {
if (isFalling) {
if (centerY > height) {
isFalling = false;
}
else
if (Math.abs(centerX - sub.centerX) <= 36 && Math.abs(centerY - sub.centerY) <= 21) {
sub.isExploding = true;
sub.explosionFrameNumber = 1;
isFalling = false; // Bomba reapare in barca
}
else {
centerY += 10;
}
}
}
void draw(Graphics g) {
if ( !isFalling ) {
centerX = boat.centerX;
centerY = boat.centerY + 23;
}
g.setColor(Color.RED);
g.fillOval(centerX - 8, centerY - 8, 16, 16);
}
}
You need to rewrite your code in terms of a list of bombs rather than a single bomb. Then, your key pressed event needs to change to add a new bomb to the list rather than just setting the properties of the single bomb. Your processing code will then also need to change - you'll need to loop over the list and process each bomb in turn.
i created a pacman game with everything in it but the problem is that the ghosts and their animation require a lot of code.
example:
every ghost needs 3 if statements at the moment that is 20 lines of code per ghost and if i have 3 ghosts in the game that is 3 x 20 = 60 lines of useless coding..
with my php experience i would say.. use a foreach loop or something similar.. but how should i do this in Java? can someone give me an example? the way i do it now is published below:
creating ghost objects;
DrawPacMan ghost1 = new DrawPacMan();
DrawPacMan ghost2 = new DrawPacMan();
and the painting goes like:
int g1x = 0;
boolean g1r = true;
public void paintComponent(Graphics g) {
super.paintComponent(g);
// pacman movement
diameter = 75;
pacman.drawPacMan(g, getHorPlaats(), getVerPlaats(), diameter, getView(), Color.yellow);
// ghosts movement
if(g1r == true) {
g1x += ghostSpeed;
}
if(g1r == false) {
g1x -= ghostSpeed;
}
if(g1x == 500 || g1x == 0) {
g1r = !g1r;
}
System.out.println(g1r);
ghost1.drawGhost(g, g1x, 40, diameter, Color.red);
ghost2.drawGhost(g, 170, 70, diameter, Color.blue);
}
It looks to me like you're not approaching this in a object-oriented fashion. Why not use a collection of ghosts eg. List<Ghost> and define a Ghost object with it's location, colour etc?
This line:
ghost1.drawGhost(g, g1x, 40, diameter, Color.red);
would then be replace with
ghost.draw(g);
and you'd iterate through the list, calling draw() for each.
for(Ghost ghost : ghosts) {
ghost.draw(g); // pass in the graphics context
}
Each ghost knows it's location, colour, state etc. and you can create as many as you like:
List<Ghost> ghosts = new ArrayList<Ghost>();
for (int i = 0; i < 10; i++) {
ghosts.add(new Ghost());
}
Since you seem to be new to Java and still getting to know the best idioms, I'll advise on something that is not directly an answer to your question, but is so in a more general sense. Your code
if(g1r == true) {
g1x += ghostSpeed;
}
if(g1r == false) {
g1x -= ghostSpeed;
}
can be rewritten as just
g1x += ghostSpeed * (g1r? 1 : -1);
A general note: never compare booleans to literal values. b == true is the same as just b and b == false is the same as !b.
This code
if (g1x == 500 || g1x == 0) {
g1r = !g1r;
}
will probably result in a bug at runtime as you don't precede it with fencing-in code: g1x can easily step over your limits. You should write instead
if (g1x >= 500) { g1x = 500; g1r = false; }
else if (g1x <= 0) { g1x = 0; g1r = true; }
Pass the ghost object as another parameter in the same function paintComponent(Graphics g, Ghost gr)
You can make the conditional statements inline, e.g. g1r == true ? g1x += ghostSpeed : g1x -= ghostSpeed
I'm trying to move sprites to stop the frames in center(or move them to certain x position) when right or left pressed on screen. There are 3 sprites created using box.java in the view, placed one after another with padding, stored in arraylist.
The problem: No smooth movement and doesn't stop in the center of each frames after movement has begun, sometimes all boxes are moving on top of each others, padding is totally lost. Please let me know what I'm doing wrong, thanks a lot!
//BEGINING OF BOX.JAVA >> The problem is in this class!
//This goes in Update();
private void boxMove()
{
int get_moved_pos = getMovedPos(); //get moved pos
int sprite_size = view.getSpriteSize(); //get sprite arraylist size
currentDirection = view.getDirection(); //get direction "left" or "right" from view
if(currentDirection == "right" && isMoving == false)
{
setSpriteMovedNext();
}else
if(currentDirection == "left" && isMoving == false)
{
setSpriteMovedPrev();
}
if(currentDirection != lastDirection)
{
lastDirection = currentDirection;
//MOVE RIGHT
if(currentDirection == "right" && get_moved_pos > 0) //move left and make sure that moved pos isn't overlapping / or moving to empty space
{
//Animate left until it reaches the new x position
if(x > get_new_pos_left)
{
x -= pSpeedX;
}
Log.d("RIGHT","POS: " + get_moved_pos);
}else
//MOVE LEFT
if(currentDirection == "left" && get_moved_pos < sprite_size-1) //move left and make sure that moved pos isn't overlapping / or moving to empty space
{
//Animate right until it reaches the new x position
if(x < get_new_pos_right)
{
x += pSpeedX;
}
}
}
}
//Call when screen is touched (in View.java), to set a new position to move to.
public void resetMoving()
{
isMoving = false;
this.lastDirection = "";
Log.d("RESET", "MOVING RESET");
}
public int getMovedPos()
{
return this.smoved_pos;
}
private void setSpriteMovedNext()
{
int get_max_moved = getMovedPos();
int s_size = view.getSpriteSize();
if (isMoving == false) //take a break between movements
{
if(get_max_moved < s_size-1)
{
Log.d("NEXT", "CALLED");
this.get_new_pos_right = x + view.getNextPosX(); //current x and next stop position
this.smoved_pos += 1;
this.isMoving = true; //set to avoid double touch
Log.d("NEXT", "X POS SET: " + get_max_moved);
}
}
}
private void setSpriteMovedPrev()
{
int get_max_moved = getMovedPos();
if (isMoving == false) //take a break between movements
{
if(get_max_moved > 0)
{
Log.d("PREV", "CALLED");
this.get_new_pos_left = x - view.getNextPosX(); //get current x pos and prev stop position
this.smoved_pos -= 1; //to limit the movements
this.isMoving = true; //set to avoid double touch
Log.d("PREV", "X POS SET: " + get_max_moved);
}
}
}
//END OF BOX.JAVA
//VIEW
//Add boxes
public void addBox()
{
int TOTAL_BOXES = 3;
int padding_left = 200;
int padding_tmp = this.getWidth()/2;
box.clear(); //clear old
//Box 1
box.add(new Boxes(box, this, "box1",
padding_tmp,
this.getHeight()/2,
boxSpriteImage, 1, 2, 0, 0));
padding_tmp += boxSpriteImage.getWidth()/TOTAL_BOXES + padding_left;
//Box 2
box.add(new Boxes(box, this, "box2",
padding_tmp,
this.getHeight()/2,
boxSpriteImage, 1, 2, 1, 1));
padding_tmp += boxSpriteImage.getWidth()/TOTAL_BOXES + padding_left;
//Box 3
box.add(new Boxes(box, this, "box3",
padding_tmp,
this.getHeight()/2,
boxSpriteImage, 1, 2, 2, 1));
}
public boolean onTouchEvent(MotionEvent event){
if (System.currentTimeMillis() - lastClick > 100){
lastClick = System.currentTimeMillis();
float x = event.getX();
float y = event.getY();
synchronized (getHolder())
{
if(isBoxWindow() == true)
{
if(x >= this.getWidth()/2)
{
Direction = "right";
}else
{
Direction = "left";
}
}
}
}
//called in box.java to get next x pos to move
public float getNextPosX()
{
int PADDING = 200; //padding between frames
next_pos_x = boxSprite.getWidth()/TOTAL_COLUMNS + PADDING;
return next_pos_x;
}
I think your error is in the if statements, where you compare currentDirection and lastDirection (I'm assuming that lastDirection is a String) with other Strings using the == operator. The == almost operator never works when you want to compare Objects for equality. You should use the equals() method.
For eg.
if(currentDirection != lastDirection)
should be written as:
if(!currentDirection.equals(lastDirection)
Make such changes in your code(They are needed at many places!) and I think your problem should be solved.
A good debugging practice would be logging data about your app, from each of the if blocks, to see if each of them is executed. You could have found out if your if statements are being executed.
EDIT: Why have you put this code?
if (System.currentTimeMillis() - lastClick > 100)
This means onTouchEvents are only interpreted after 100ms. remove it and check, probably that's what is causing the problem.
Alrite, decided to use onFling() method and call via View instead of adding the animations separately into the class itself, works really well when called box.get(i).update() in a loop of all added boxes, all of them animated equally. Thanks udiboy.
I'm wondering how I can move an image after it has been drawn?
Heres my code for drawing the image:
public int probeX = 500;
public int Minerals = 400;
public int drawProbeA, drawProbe = 0;
public void init() {
// Images Call
probe = getImage(getDocumentBase(), "image/probe.png");
}
public void paint(Graphics g) {
if (drawProbe == 1) {
for (int k = 0; k < drawProbeA; k++) {
g.drawImage(probe, probeX, 474, 50, 50, this);
probeX += 50;
}
probeX = 500;
}
}
public boolean mouseDown(Event e, int x, int y) {
// Clicking on the probe icon
if (x > 1068 && x < 1119 && y > 785 && y < 832 && onNexus == 1
&& Minerals >= 50) {
drawProbeA += 1;
drawProbe = 1;
Minerals -= 50;
}
return true;
}
How can I make it so that after the images are drawn, that hitting an icon will cause the image to be auto moved down the y-axis (like 50 pixels)? Basically, like sliding the image down with an animation? And then stop and then move back up to the orginal spot.
I am using an Applet and would like the animation to loop repeatedly. Thanks.
You need to have a global variable, or another variable somewhere, that indicates that...
The image needs to move
How far in the Y direction it has moved already
Which direction it is going (up or down)
When you have this, you need to add code to your paint() method to draw the image in the correct spot.
You would also need a Timer or Thread that will tell the component to repaint() every few milliseconds, and change your global variables so that it will repaint it lower/higher.
So, as a bit of an example, you might have some global variables like this...
int yPosition = 0;
boolean goingDown = true;
When you need to start your animation, start a Timer that calls the following over and over...
if (goingDown == true){
// if we've gone down 50 pixels, start going up again
if (yPosition <= 0){
goingDown = false;
yPosition++;
}
else {
yPosition--; // move it down 1 pixel
}
}
else {
// if we're going up and we reach 0, go down again
if (yPosition >= 50){
goingDown = true;
yPosition--;
}
else {
yPosition++; // move it up1 pixel
}
}
component.repaint(); // this will call the paint() method
Not your paint method just need to draw your image at the different position. Just change the g.drawImage(probe,probeX,474,50,50,this); like to include the yPosition...
g.drawImage(probe,probeX,474+yPosition,50,50,this);
This should at least point you in the right direction.