JAVA Greenfoot Game Over / Win check on yCoordinate - java

I'm having this issue with my 2 checks for a frogger-style game.
So the Gameover check is a simple collision check on the frog object.
The next check does a getY coord check for checking if the frog object has hit the roof of the world ergo has beaten the game.
Now when the GameOver check is fulfilled there is no more object to do a getY check on. So it gives an error.
How can I bypass this ?
full code of the Frogger class:
public class Frogger extends Actor
{
public void act()
{
checkKeys();
hitEnemy();
atTop();
}
private void checkKeys()
{
if (Greenfoot.isKeyDown("up")) {
setLocation(getX(), getY()-3);
}
if (Greenfoot.isKeyDown("down")) {
setLocation(getX(), getY()+3);
}
if (Greenfoot.isKeyDown("left")) {
setLocation(getX()-3, getY());
}
if (Greenfoot.isKeyDown("right")) {
setLocation(getX()+3, getY());
}
}
public void hitEnemy()
{
Actor Enemy = getOneIntersectingObject(Enemy.class);
if(Enemy != null)
{
World myWorld = getWorld();
Gameover gameover = new Gameover();
myWorld.addObject(gameover, 300, 200);
myWorld.removeObject(this);
}
}
private void atTop()
{
if (getY() < 30)
{
World myWorld = getWorld();
Youwin youwin = new Youwin();
myWorld.addObject(youwin, 300, 200);
myWorld.removeObject(this);
}
}
}

Different approaches. When the game is over, you could just not do a getY() check anymore. Do not continue running the game, but rather to back to a main menu or something. the getY() method is irrelevant here. You could halt the program completely.
But your code looks weird. GameOver is an object? Rather than a simple method in your game. It does look like your code has a weird structure for a game. Anyway, when the game is over the 'gamelogic' loop should no longer be running, bur rather go to a menu.
Or you could keep the game running and do a null check. But reading your code, it seems like the whole structure is not that good. Is the aTop part of your Frog class? If so, it should exist for it to be called on. If you remove the Frog class from the world, you could do something like (but I do not see where the aTop method gets called)
if(myWorld.getFrog()!=null){
// Get method
}
Could you maybe share a bit more of your code? I think this should give you an idea though, there should be no more calls to the object when the object is removed, because the game ended and the normal game loop should no longer be running. And otherwise, nullchecks.

Related

How do I detect the collision between the bullet and the enemy? [duplicate]

This question already has answers here:
Ball to Ball Collision - Detection and Handling
(15 answers)
Closed last year.
I'm creating a shooter game and im unsure on how to make it detect the fact that the bullet has hit the enemy. This is the boolean that was given
boolean isShot(Bullet bullet) //is shot sequence
{
if (bullet!=null)
{
if (abs(this.x - bullet.x) < 20 &&
abs(this.y - bullet.y) < 20)
return true;
}
return false;
}
and this is the part where i try make it detect the collision and make the enemy disappear but it keeps giving me errors no matter what i try.
import java.util.ArrayList;
int score;
Player p1;
Enemy[] e= new Enemy[4];
ArrayList<Bullet> bullet = new ArrayList<Bullet>();
void setup()
{
size (1000, 1000);
p1= new Player(500,5, 40);
e[1]= new Enemy(100,1000,3);
e[2]= new Enemy(500,800,3);
e[3]= new Enemy(700,700,3);
// b1= new Bullet(500,500,-5);
}
void draw()
{
background(255);
p1.render();
e[1].render();
e[1].move();
e[2].render();
e[2].move();
e[3].render();
e[3].move();
text("Score:" + score,50,50);
for (Bullet b: bullet)
{
b.render();
b.move();
}
if (e[1].isShot(Bullet))
{
e[1]=null;
}
Its at the bottom of this peice of code. When i try put bullet in lowercase it says "the function isShot() expects paramaters like "isShot(Bullet)" but when i capitalise the B in bullet it tells me that bullet isnt a variable.
"bullet" with lowercase b is an array of Bullets, but isShot() expects a single Bullet object. And "Bullet" with capital B is not a variable, but a class (I suppose).
So, you either need to create another object of Bullet or use one of the Bullet object in your "bullet" ArrayList.
You are almost there.
I suggest you use more meaningful names for your parameters.
First of all, you have to populate the ArrayList bullet in your setup() or elsewhere you want in your code.
After this, if you want to check that condition using isShot function you should pass to it an instance of an Object, not the class Object itself.
This can be easily achieved by including the function in your for loop.
While it is always good to practice, I suggest you to first understand the basics of the language and then move to more complex examples (custom classes, arrays iterations and so on).
void setup()
{
size (1000, 1000);
p1= new Player(500,5, 40);
e[1]= new Enemy(100,1000,3);
e[2]= new Enemy(500,800,3);
e[3]= new Enemy(700,700,3);
bullet.add(new Bullet(500,500,-5)); // e.g. to populate array
}
void draw()
{
background(255);
p1.render();
e[1].render();
e[1].move();
e[2].render();
e[2].move();
e[3].render();
e[3].move();
text("Score:" + score,50,50);
for (Bullet b: bullet)
{
b.render();
b.move();
if (e[1].isShot(b)) // now you can use b which is an instance of Bullet
{
e[1]=null;
}
}

Box2D (Processing): how to solve the 'Could not invoke the "beginContact()" method for some reason' error?

First of all, check this out (link): it's an example program taken from the Processing Box2D library on github, which displays a box at the center of the screen (it can be moved around with the mouse) while a cascade of little balls fall on it; whenever a ball hits the box, that ball turns red. I copypasted the four .pde files into a single .pde sketch, run it, and it works perfectly.
Now, onto my problem. I'm currently making a game in Processing: you have a ball, a player 1 and a player 2 (both of which can be moved around using the keyboard). Box2D is in charge of the physical interactions between each player and the ball, and I must say it handles them pretty well. Each of the three main objects has its own class. Now, I want stuff to happen as soon as player 1 makes contact with the ball. And that example code seems perfect for this scope, right? It works on my computer, after all.
So, I started copying the relevant parts:
I copypasted all the 'import's at the beginning of my code;
I added box2d.listenForCollisions(); inside setup();
I also added these two functions at the very bottom of my sketch:
void beginContact(Contact cp) {
Fixture f1 = cp.getFixtureA();
Fixture f2 = cp.getFixtureB();
Body b1 = f1.getBody();
Body b2 = f2.getBody();
Object o1 = b1.getUserData();
Object o2 = b2.getUserData();
if (o1.getClass() == Box.class) {
Particle p = (Particle) o2;
p.change();
}
else if (o2.getClass() == Box.class) {
Particle p = (Particle) o1;
p.change();
}
}
void endContact(Contact cp) {
}
Which I promptly changed into this (I basically renamed the classes, and substituted p.change(), the method that turned the balls red in that sketch, with what I want to happen when contact is being made):
(... same ...)
if (o1.getClass() == Player.class) {
Ball p = (Ball) o2;
//do stuff when contact happens
}
else if (o2.getClass() == Player.class) {
Ball p = (Ball) o1;
//do stuff when contact happens
}
}
void endContact(Contact cp) {
}
But guess what? I get a 'Could not invoke the "beginContact()" method for some reason' error! I don't think I'm lacking any crucial files or libraries, since that example worked fine in my computer and all I did was just copypaste and run the code.
I cannot paste here my whole code because it's huge, but I swear the Player class (player 1 class), the Enemy class (player 2 class) and the Ball class all have their fixtures, and there's literally nothing in my classes that differs in a substantial way from those from the example sketch. The bodies are all of dynamic type, the players are rectangular boxes like the box in the example, and the ball is a pure circle like the little balls that turned red there.
What is happening? Did I miss an important line from that code? Even though the example code runs perfectly without needing any additional files, I should mention that the console also prints an 'at shiffman.box2d.Box2DContactListener.beginContact(Box2DContactListener.java:54)' error: now, like I said, I don't need that Box2DContactListener.java file in my computer to run the example sketch... but anyway, if I read it up online (link), I can see this is what it's referring to:
public void beginContact(Contact c) {
if (beginMethod != null) {
try {
beginMethod.invoke(parent, new Object[] { c });
} catch (Exception e) {
System.out.println("Could not invoke the \"beginContact()\" method for some reason.");
e.printStackTrace();
beginMethod = null;
}
}
}
Do you have any idea what's going on here?
Basically, before the if statement, you have to check if either of the objects is 'null'.
In case it is, you just have to break.
You can just simply paste this:
if (o1==null || o2==null)
return;

Why is it adding more than 1 to my speed control?

import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
public class Turtle extends Actor
{
/**
* Act - do whatever the Turtle wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
int laufmenge;
public void act()
{
if(Greenfoot.isKeyDown("left")){
move(-speed);
}
if(Greenfoot.isKeyDown("right")){
move(speed);
}
if(Greenfoot.isKeyDown("up")){
setLocation(getX() ,getY() -speed);
}
if(Greenfoot.isKeyDown("down")){
setLocation(getX() ,getY() +speed);
}
if(Greenfoot.isKeyDown("x")){
if(speed<10) speed++;
}
if(Greenfoot.isKeyDown("y")){
if(speed>0) speed--;
}
System.out.println(speed);
}
private int speed=1;
}
This is code from Greenfoot because i am currently trying to learn coding. I cant understand why when i execute the programm and control the speed he is changing the value by more than one. I guess it will be an easy question.
And is it possible to put the increase and decrease of the speed on one button with two letters like the >< key? i didnt work in my case.
This happens because act() is called in rapid succession. Even if you just press and release x, act() will have run several times while the key is down, and therefore updated the speed several times.
To avoid that, you can track whether or not you've adjusted the speed since the first time you noticed that the button was pressed.
For example, you can have a private bool adjustedSpeed = false; in your class, and then do:
if(Greenfoot.isKeyDown("x")){
if(speed<10 && !adjustedSpeed) speed++;
adjustedSpeed = true;
} else if(Greenfoot.isKeyDown("y")){
if(speed>0 && !adjustedSpeed) speed--;
adjustedSpeed = true;
} else {
adjustedSpeed = false
}

How to activate a function within an loop to continue after exiting loop

i'm sure I can figure this out on my own but I feel like the way i'm writing it is already too expensive and coupled.
I am writing a simulator with a security robot and a intruder, I have a collision function, where in the 3rd if statement it checks if an intruder (rectangle of width 11) collides with an surveillance camera (arc) and if that happens then I want to activate my function for the security robot to chase the intruder.
<-- Important note: the checkShapeIntersection function is inside a timeLine event so its running constantly -->
private boolean checkShapeIntersection(Shape block) {
//Name to check for intruder and surveillance collision
String Surveillance = "Arc";
boolean collisionDetected = false;
for (Shape static_bloc : nodes) {
if (static_bloc != block) {
Shape intersect = Shape.intersect(block, static_bloc);
if (intersect.getBoundsInLocal().getWidth() != -1) {
collisionDetected = true;
//Checks of intruder collides with an arc (surveillance), the 11th width is only for intruder rectangles
if ( Surveillance.equals(block.getClass().getSimpleName()) && static_bloc.getBoundsInLocal().getWidth() == 11) {
//Activate Chase function
testRobot.chaseIntruder(static_bloc);
detected = true;
}
}
}
}
if (collisionDetected) {
block.setFill(Color.BLUE);
} else {
block.setFill(Color.RED);
}
return detected;
}
And inside my Security Robot Class
public void chaseIntruder(Shape intruder) {
destinationsList.add(new Vector2D(intruder.getLayoutBounds().getMinX(),intruder.getLayoutBounds().getMinY()));
this.updatePosition();
}
You probably want to use multi-threading here, in Java you can implement Runnable or Thread to achieve wanted functionality.
Here are some links with more info:
In a simple to understand explanation, what is Runnable in Java?
https://docs.oracle.com/javase/7/docs/api/java/lang/Runnable.html
https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html
https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html
Hope it helps.

Programming Video Games for the Evil Genius:Project 10:Radical Racing-The Cars

Iv'e looked all over for answers to this book. And I know anyone else who has tried to read this book feels the same way. It's called "Programming Video Games for The Evil Genius" Is there anyone who has read this book? I'm on project 10:Radical Racing-The Cars. Everything compiles correctly but for some reason my cars are not showing up in the correct spot on the JFrame. They should be showing up under the two white lines. I'm positive the code is exactly the same as in the book, but the book is wrong. I have already tried changing the HEIGHT part of the point of origin but no matter what I do it does not budge. I can't attach an image because I don't have a rep of at least 10 .This is the code that the deals with the placement of the cars.
public class TheCars extends JFrame
{
final int WIDTH = 900; int HEIGHT = 650;
double p1Speed = .5, p2Speed = .5;
Rectangle p1 = new Rectangle(WIDTH/9,HEIGHT/2, WIDTH/30,WIDTH/30);
Rectangle p2 = new Rectangle(((WIDTH/9)+((int)((WIDTH/9)*1.5)/2)),(HEIGHT/2)+
(HEIGHT/10),WIDTH/30,WIDTH/30);
//the constructor
public TheCars()
{
//the following code creates the JFrame
super("Radical Racing");
setSize(WIDTH,HEIGHT);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
//start the inner class (which works on it's own because it is a thread)
Move1 m1 = new Move1();
Move2 m2 = new Move2();
m1.start();
m2.start();
}
//this will draw the cars and the racetrack
public void paint(Graphics g)
{
super.paint(g);
//set the color to blue for p1
g.setColor(Color.BLUE);
//now draw the actual player
g.fill3DRect(p1.x,p1.width,p1.width,p1.height,true);
//set the color to red for p2
g.setColor(Color.red);
//now draw the actual player
g.fill3DRect(p2.x,p2.width,p2.width,p2.height,true);
}
private class Move1 extends Thread
{
public void run()
//This should all be in an infinite loop so that the process repeats.
{
while(true)
{
//now put in the try block. This will let
//the program exit if there is an error
try
{
//first refresh the screen
repaint();
//increase speed a bit
if(p1Speed<=5)
p1Speed+=.2;
p1.y-=p1Speed;
//this delays the refresh rate
Thread.sleep(75);
}
catch(Exception e)
{
//if there is an exception (an error), exit the loop
break;
}
}
}
}
private class Move2 extends Thread
{
public void run()
{
//this should all be in an infinite loop so the process repeats
while(true)
{
//now put the code in a "try" block.
//this will let the program exit if there is an error
try
{
//first refresh the screen
repaint();
//increase the speed a bit
if(p2Speed<=5)
p2Speed+=.2;
p2.y-=p2Speed;
//this delays the refresh rate
Thread.sleep(75);
}
catch(Exception e)
{
//if there is an exception (an error), exitthe loop
break;
}
}
}
}
public static void main(String[]args)
{
new TheCars();
}
}
Assuming you're painting those Rectangle objects directly onto the screen, we have to assume that the expressions "HEIGHT/2" and "HEIGHT/2 + HEIGHT/10" are coming out equal, and nonzero but small. That would be the case if HEIGHT is an int, and the value is more than 2 and less than 10. Presumably the value would need to be a couple hundred, at least, for those boxes to show up in the middle of the screen. Check the value of HEIGHT (just using a System.out.println() would be fine) and make sure it's the actual height of the window.
EDIT
Now that we see the rest of the code: the second argument to each call to fill3DRect() is wrong. It should be the y member of the Rectangle objects, which is a large, varying number, but you're passing the width member, which is a small fixed number. Change both the calls to look like this and you'll be back on track:
g.fill3DRect(p1.x, p1.y, p1.width, p1.height, true);

Categories

Resources