I am currently making a collision detection in java, I have a two objects coming from a different class which is a bird and a worm. The worm moves in a random direction while the bird move only when I want him to move because I'm the one who's controlling him by using key arrow buttons. Now, if the two objects collide I want only the worm to be vanish and the bird will remain there. Could somebody help me how to do that? Thanks in advance for sharing your ideas.
This codes is coming from my World class.
public void render()
{
setupStrategy();
x0_pixel = 0;
y0_pixel = 0;
x1_pixel = getWidth();
y1_pixel = getHeight();
x1_world = x1_pixel / meter;
y1_world = y1_pixel / meter;
Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();
g2d.setBackground(Color.lightGray);
g2d.clearRect(0, 0, x1_pixel, y1_pixel);
g2d.setColor(Color.BLACK);
for (double x = 0; x < x1_world; x++)
{
for (double y = 0; y < y1_world; y++)
{
int xx = convertToPixelX(x);
int yy = convertToPixelY(y);
g2d.drawOval(xx, yy, 2, 2);
}
}
for (Worm worm : worms)
{
for (Sprite bird : birds)
{
if (!collides())
{
bird.render(g2d);
worm.render(g2d);
}
}
}
g2d.dispose();
strategy.show();
Toolkit.getDefaultToolkit().
sync();
}
public void start() throws InterruptedException
{
long prevLoopStart = System.nanoTime();
Avg avg = new Avg();
while (true)
{
final long loopStart = System.nanoTime();
final long dt = loopStart - prevLoopStart;
for (Worm worm : worms)
{
worm.move(dt);
}
for (Bird bird : birds)
{
bird.move(dt);
}
render();
Collides();
frame.onFpsUpdated(1.0 / dt * SECOND, avg.add(loopStart));
final long elapsed_ns = System.nanoTime() - loopStart;
long expected_elapsed_ms = 1000 / 60;
long elapsed_ms = (long) (elapsed_ns / (1000.0 * 1000.0));
long sleep_ms = expected_elapsed_ms - elapsed_ms;
if (sleep_ms > 0)
{
Thread.sleep(sleep_ms /* ms */);
}
prevLoopStart = loopStart;
}
}
private boolean Collides()
{
ArrayList<Sprite> toDisappear = new ArrayList<Sprite>();
for (int i = 0; i < worms.size(); i++)
{
Sprite r1 = worms.get(i);
for (int j = i + 1; j < birds.size(); j++)
{
Sprite r2 = birds.get(j);
if (r1 == r2)
{
continue;
}
Rectangle me = r1.getBounds();
Rectangle him = r2.getBounds();
if (me.intersects(him))
{
collision = true;
toDisappear.add(r1);
toDisappear.add(r2);
}
toDisappear.remove(r1);
todisappear.remove(r2);
}
}
return collision;
}
This book provides a lot of INFO regarding "Collision Detection" ( Read Chapter 2 and 3 ) and other topics related to Game programming in Java.
http://fivedots.coe.psu.ac.th/~ad/jg/
There are open source frameworks that already do that. If you are doing it for learning purposes then just check their code.
One is Genuts and it SpriteCollisionManager.
The resource that #Upul mention is also of great value.
Regards.
you have a nested for-loop which checks for collisions between birds and worms. if there is a collision neither of them are drawn. Your code also incorrectly draws birds and worms multiple times.
for (Worm worm : worms){
for (Sprite bird : birds){
if (!collides()){
bird.render(g2d);
worm.render(g2d);
}
}
}
The correct way to go is to remove the worm from the list when there is a collision:
for (Iterator<Worm> wit = worms.getIterator(); wit.hasNext(); ){
Worm worm = wit.next();
for (Sprite bird : birds){
if (worm.collidesWith(bird)){
wit.remove();
break;
}
}
}
for (Worm worm : worms){
worm.render(g2d);
}
for (Sprite bird : birds){
bird.render(g2d);
}
Now I assume that you will implement a boolean collidesWith(Bird other) method in class worm so that you can compare that specific worm with the bird you got as an argument. Alternatively make a function as such:
boolean collidesWormBird(Sprite worm, Sprite bird){
Rectangle me = worm.getBounds();
Rectangle him = bird.getBounds();
return me.intersects(him);
}
Related
Hello Stack Overflow people :)
I'm a huge newbie when it comes to coding, and I've just ran into a problem that my brain just won't get over...
Before I start blabbering about this issue, I'll paste my code so as to give a little bit of context (sorry in advance if looking at it makes you wanna puke). The main focus of the issue is commented and should therefore be fairly visible :
Main
ArrayList<Individual> individuals = new ArrayList<Individual>();
void setup()
{
size(500,500);
for(int i = 0; i < 2; i++)
{
individuals.add(new Individual());
}
println(frameRate);
}
void draw()
{
background(230);
for(int i = 0; i < individuals.size(); i++)
{
individuals.get(i).move();
individuals.get(i).increaseTimers();
individuals.get(i).display();
}
}
Individual
class Individual
{
float x;
float y;
int size = 5;
Timer rdyBreed; /* Here is the object that appears to be shared
between individuals of the ArrayList */
float breedRate;
float breedLimit;
Individual()
{
x = random(0, width);
y = random(0, height);
rdyBreed = new Timer("rdyBreed", 0);
breedRate = random(.2, 3);
breedLimit = random(10, 20);
}
void move()
{
int i = (int)random(0, 1.999);
int j = (int)random(0, 1.999);
if (i == 0)
{
x = x + 1;
} else
{
x = x - 1;
}
if (j == 0)
{
y = y + 1;
} else
{
y = y - 1;
}
checkWalls();
}
void checkWalls()
{
if (x < size/2)
{
x = width - size/2;
}
if (x > width - size/2)
{
x = size/2;
}
if (y < size/2)
{
y = width - size/2;
}
if (y > width - size/2)
{
y = size/2;
}
}
void display()
{
noStroke();
if (!rdyBreed.finished)
{
fill(255, 0, 0);
} else
{
fill(0, 255, 0);
}
rect(x - size/2, y - size/2, size, size);
}
void increaseTimers()
{
updateBreedTimer();
}
void updateBreedTimer()
{
rdyBreed.increase(frameRate/1000);
rdyBreed.checkLimit(breedLimit);
rdyBreed.display(x, y);
}
}
Timer
class Timer
{
float t;
String name;
boolean finished = false;
Timer(String name, float t)
{
this.t = t;
this.name = name;
}
void increase(float step)
{
if (!finished)
{
t = t + step;
}
}
void checkLimit(float limit)
{
if (t >= limit)
{
t = 0;
finished = true;
}
}
void display(float x, float y)
{
textAlign(RIGHT);
textSize(12);
text(nf(t, 2, 1), x - 2, y - 2);
}
}
Now that that's done, let's get to my question.
Basically, I'm trying to create some sort of a personal Conway's Game of Life, and I'm encountering a lot of issues right off the bat.
Now my idea when writing this piece of code was that every individual making up the small simulated "society" would have different timers and values for different life events, like mating to have children for example.
Problem is, I'm not a huge pro at object-oriented programming, and I'm therefore quite clueless as to why the objects are not having each their own Timer but both a reference to the same timer.
I would guess making an ArrayList of timers and using polymorphism to my advantage could make a change, but I'm not really certain of it or really how to do it so... yeah, I need help.
Thanks in advance :)
EDIT : Here is a screenshot of the debugger. The values keep being the same with each iteration of the updates.
Screenshot
What makes you think they reference the same Timer object? The values of t displayed in the debugger are going to be the same until one of them reaches the breedLimit and gets set to 0, because they're being initialized at the same time.
Try this and see that the values of t are different.
void setup() {
size(500,500);
}
void mouseClicked() {
individuals.add(new Individual());
}
I'd recommend setting the breakpoint somewhere around here:
t = 0;
finished = true;
They do not share the same timer, you create a new Timer object for each Individual.
class Individual {
// ...
Timer rdyBreed;
Individual() {
// ...
rdyBreed = new Timer("rdyBreed", 0);
//...
The only way they could be sharing the same Timer is if you were setting rdyBreed elsewhere, but since you don't want that I recommend making it final.
If you did want to share the same Timer instance across all individuals then you could declare it static.
Need some help modifying this code. I was working through some tutorials on particle systems, and I'm currently trying to write seom logic that says:
"If this particle system has been running for 10 seconds, stop adding particles to it. When the last of the particles are dead, and the system is empty,remove it from the systems ArrayList."
What is going on now:
- The timer counts down and particles stop being added to the particle system except it is acting like a timer for every particle system in the array list.
- the timer does not reset when you add a new particle system
What I need help with:
- Where to reset the timer, or re-initialize the timer when you make a new system.
- only having the timer affect the system its in (rather than all of them on screen)
// particle system
class ParticleSystem {
ArrayList<Particle> plist;
PVector origin; // An origin point for where particles are birthed
float c;
int t;
int countdown; // 10 seconds.
boolean end;
ParticleSystem(float col, int num, PVector v){
plist = new ArrayList<Particle>();
origin = v.get();
c = col;
end = false;
countdown = 10;
t = 10;
for(int i = 0; i < num; i++){
plist.add(new Particle(c,origin));
}
}
void applyForce(PVector force){
for (Particle p : plist){
p.applyForce(force);
}
}
void run(){
// iterate through array of single particles backwards
// remove single particles when they are dead.
t = countdown-int(millis()/1000);
print(t);
for (int i = plist.size()-1; i > 0; i--){
Particle p = plist.get(i);
p.run();
if (p.isDead()){
plist.remove(i);
}
}
if(t > 0){
addParticle();
} else {
dead();
}
//print(plist.size());
}
void addParticle(){
//println("AP: "+r);
float r = random(1);
if (r<0.4) {
plist.add(new SquareParticle(c,origin));
}else{
plist.add(new Particle(c,origin));
}
}
boolean dead(){
if(plist.isEmpty() || plist.size() == 1){
t = 10;
return true;
}else{
return false;
}
}
}
// main tab
ArrayList<ParticleSystem> systems;
PVector windRight = new PVector(0.1,0);
PVector sortaSpeed = new PVector(0,0.1);
PVector gravity = new PVector(0,0.05);
boolean wR = false;
boolean sP = false;
void setup() {
size(640,480);
systems = new ArrayList<ParticleSystem>();
noStroke();
}
void draw() {
background(0);
if(!systems.isEmpty()){
for (int i =0; i < systems.size(); i++){
ParticleSystem ps = systems.get(i);
ps.applyForce(gravity);
ps.run();
if(wR){
ps.applyForce(windRight);
}
if(sP){
ps.applyForce(sortaSpeed);
}
if(ps.dead()){
systems.remove(ps);
}
//print(systems.size());
}
} else {
fill(255);
text("'w' controls wind, 'a' controls speed, 's' adds particle systems",1,height-30);
}
}
void keyPressed() {
if(key == 'w'){
wR = true;
} else if(key == 'a'){
//print('a');
sP = true;
}else{
systems.add(new ParticleSystem(random(100,200),10,new PVector(random(10,630),10))); //random(480)
}
}
void keyReleased(){
if(key == 'w'){
wR = false;
} else if(key == 'a'){
sP = false;
}
}
In the future, please try to post an MCVE. Right now we can't run your code because it contains compiler errors. We don't need to see your entire sketch anyway though, just a small example that gets the point across.
But looking at your code, there is a problem here:
for (int i =0; i < systems.size(); i++){
...
if(ps.dead()){
systems.remove(ps);
}
Run through an example using a piece of paper and a pencil. Let's say you have 3 ParticleSystem instances in your systems list, and the loop is on the second one. You then remove the second one, moving the third one into the second index. The next iteration of the loop moves to the third index... but now there's nothing there!
To get around this problem, you could iterate through the ArrayList backwards, or better yet, you could use an Iterator.
From there it's just a matter of keeping track of each instance's startTime and comparing that to millis(), which you aren't doing right now.
Here's an MCVE that demonstrates using millis() and an Iterator to kill off Particle instances after 10 seconds:
import java.util.Iterator;
ArrayList<Particle> particles = new ArrayList<Particle>();
void setup() {
size(500, 500);
}
void draw() {
background(0);
Iterator<Particle> particleIterator = particles.iterator();
while (particleIterator.hasNext()) {
Particle p = particleIterator.next();
p.draw();
if (p.isDead()) {
particleIterator.remove();
}
}
}
void mousePressed() {
particles.add(new Particle(mouseX, mouseY));
}
class Particle {
int startTime;
float x;
float y;
public Particle(float x, float y) {
startTime = millis();
this.x = x;
this.y = y;
}
void draw() {
x += random(-2, 2);
y += random(-2, 2);
ellipse(x, y, 10, 10);
}
boolean isDead() {
return millis() > startTime + 10*1000;
}
}
Note that you'll have to use this logic twice: once for your individual particles, and again for the particle systems themselves. But the logic is the same: record a start time, then compare that to millis(), and use an Iterator to remove stuff when it has timed out.
Also note that Iterator is specific to Java mode. If you want to deploy as JavaScript, you might want to go with the backwards loop approach instead.
Hello I have a programme where you place tiles to build houses and then you sell the houses. I only want to sell the houses if the building has a door an at least one window.
My arraylist looks like this:
public static ArrayList<block> b = new ArrayList<block>();
every type of tile has an id. the door tile is 1 and the windows tile is 2 and the wall tile is 3.
for(int i = 0; i < play.b.toArray().length;i++){
if(play.b.contains(play.b.get(i).id == 1)){
cansell= true;
}else{
cansell= false;
}
}
How can I check to see if an object in an arraylist contains a certain value , in this case the value 1.
here is the door class:
public class door extends block{
public cockpit(int x,int y,int rot){
this.x = x;
this.y = y;
this.rotate = rot;
r = new Rectangle(x - (int)play.camx,y - (int)play.camy,20,20);
id = 3;
}
public void tick(){
createCollisionRect();
if(Comp.mr && r.contains(new Point((Comp.mx ) ,(Comp.my) ))){
remove = true;
}
if(remove){
//play.gui.money +=800;
}
}
public void render(Graphics g){
Graphics2D g2 = (Graphics2D) g;
if (rotate == 0) {
ImageIcon i62 = new ImageIcon("res/tiles/cockpit.png");
img = i62.getImage();
g.drawImage(img, x - (int) play.camx, y - (int) play.camy,20,20, null);
}
if (rotate == 1) {
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
at.rotate(Math.toRadians(90),10,10);
ImageIcon i62 = new ImageIcon("res/tiles/cockpit.png");
img = i62.getImage();
g2.drawImage(img,at, null);
}
if (rotate == 2) {
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
at.rotate(Math.toRadians(180),10,10);
ImageIcon i62 = new ImageIcon("res/tiles/cockpit.png");
img = i62.getImage();
g2.drawImage(img, at, null);
}
if (rotate == 3) {
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
at.rotate(Math.toRadians(-90),10,10);
ImageIcon i62 = new ImageIcon("res/tiles/cockpit.png");
img = i62.getImage();
g2.drawImage(img, at, null);
}
}
}
This seems quite straight forward.
Note there is no need to get "id" ... the ArrayList stores the values itself.
You simply need to check if the index placement value in the array contains the value you are looking for:
for(int i = 0; i < play.b.toArray().length;i++){
String valueID = play.b.get(i);
if(valueID.contains("1")){
cansell= true;
}else{
cansell= false;
}
}
That should answer your question, if not, this really does help: JArrayLists
Hope this answers your question.
Let me know of the outcome
if(play.b.contains(play.b.get(i).id == 1)){ will evaluate to something like if(play.b.contains(true)){ (or false respectively). So, since you have int in your ArrayList you should change the code following:
cansell = play.b.contains(1);
instead the whole loop.
Per the update in comments:
public void canSell () {
cansell = play.b.contains(1) && play.b.contains(2);
}
From: Oracle Java Docs on Lists
I'm trying to make a 2D game. I have an array of rectangles to represent attacks. I am trying to make them rotate so they are all rotated 45 degrees. When I try rendering more spells after the first, they glitch to random places around the screen. Here is my code:
Rectangle[] waterBolt = new Rectangle[10];
float[] wba = new float[10];
int wbc = 0;
Graphics2D[] gwb = new Graphics2D[10];
public void renderSpell(Graphics2D g) {
for(int i=0; i<10; i++) {
if (waterBolt[i] != null) {
gwb[i] = (Graphics2D) g;
gwb[i].rotate(Math.toRadian(45), waterBolt[i].x, waterBolt[i].y);
gwb[i].fill(waterBolt[i]);
}
}
}
public void castSpell(int spellID) {
waterBolt[wbc] = new Rectangle(playerX, playerY, 16, 16);
wba[wbc] = (float) Math.toRadians(Math.atan2(mouseX - playerX, mouseY - playerY));
wbc++;
if (wbc >= 10) {
wbc = 0;
}
}
And here is what is happening to my screen when I cast them all standing still:
They all rotate 45 more degrees every time I click to cast, but I don't know how to fix it.
Keep in mind that when you call gwb[i] = (Graphics2D) g;, you are not making a copy of g. Instead, each of your rectangles is being rotated by the cumulative sum of all of your previous rotations. Try something like this instead:
public void renderSpell(Graphics2D g) {
AffineTransform transform = g.getTransform();
for(int i=0; i<waterBolt.length; i++) {
if (waterBolt[i] != null) {
g.rotate(Math.toRadian(45), waterBolt[i].x, waterBolt[i].y);
g.fill(waterBolt[i]);
g.setTransform(transform); // back to original orientation
}
}
}
I am developing a game in java just for fun. It is a ball brick breaking game of some sort.
Here is a level, when the ball hits one of the Orange bricks I would like to create a chain reaction to explode all other bricks that are NOT gray(unbreakable) and are within reach of the brick being exploded.
So it would clear out everything in this level without the gray bricks.
I am thinking I should ask the brick that is being exploded for other bricks to the LEFT, RIGHT, UP, and DOWN of that brick then start the same process with those cells.
//NOTE TO SELF: read up on Enums and List
When a explosive cell is hit with the ball it calls the explodeMyAdjecentCells();
//This is in the Cell class
public void explodeMyAdjecentCells() {
exploded = true;
ballGame.breakCell(x, y, imageURL[thickness - 1][0]);
cellBlocks.explodeCell(getX() - getWidth(),getY());
cellBlocks.explodeCell(getX() + getWidth(),getY());
cellBlocks.explodeCell(getX(),getY() - getHeight());
cellBlocks.explodeCell(getX(),getY() + getHeight());
remove();
ballGame.playSound("src\\ballgame\\Sound\\cellBrakes.wav", 100.0f, 0.0f, false, 0.0d);
}
//This is the CellHandler->(CellBlocks)
public void explodeCell(int _X, int _Y) {
for(int c = 0; c < cells.length; c++){
if(cells[c] != null && !cells[c].hasExploded()) {
if(cells[c].getX() == _X && cells[c].getY() == _Y) {
int type = cells[c].getThickness();
if(type != 7 && type != 6 && type != 2) {
cells[c].explodeMyAdjecentCells();
}
}
}
}
}
It successfully removes my all adjacent cells,
But in the explodeMyAdjecentCells() method, I have this line of code
ballGame.breakCell(x, y, imageURL[thickness - 1][0]);
//
This line tells the ParticleHandler to create 25 small images(particles) of the exploded cell.
Tough all my cells are removed the particleHandler do not create particles for all the removed cells.
The problem was solved youst now, its really stupid.
I had set particleHandler to create max 1500 particles. My god how did i not see that!
private int particleCellsMax = 1500;
private int particleCellsMax = 2500;
thx for all the help people, I will upload the source for creating the particles youst for fun if anyone needs it.
The source code for splitting image into parts was taken from:
Kalani's Tech Blog
//Particle Handler
public void breakCell(int _X, int _Y, String URL) {
File file = new File(URL);
try {
FileInputStream fis = new FileInputStream(file);
BufferedImage image = ImageIO.read(fis);
int rows = 5;
int colums = 5;
int parts = rows * colums;
int partWidth = image.getWidth() / colums;
int partHeight = image.getHeight() / rows;
int count = 0;
BufferedImage imgs[] = new BufferedImage[parts];
for(int x = 0; x < colums; x++) {
for(int y = 0; y < rows; y++) {
imgs[count] = new BufferedImage(partWidth, partHeight, image.getType());
Graphics2D g = imgs[count++].createGraphics();
g.drawImage(image, 0, 0, partWidth, partHeight, partWidth * y, partHeight * x, partWidth * y + partWidth, partHeight * x + partHeight, null);
g.dispose();
}
}
int numParts = imgs.length;
int c = 0;
for(int iy = 0; iy < rows; iy ++) {
for(int ix = 0; ix < colums; ix++) {
if(c < numParts) {
Image imagePart = Toolkit.getDefaultToolkit().createImage(imgs[c].getSource());
createCellPart(_X + ((image.getWidth() / colums) * ix), _Y + ((image.getHeight() / rows) * iy), c, imagePart);
c++;
} else {
break;
}
}
}
} catch(IOException io) {}
}
You could consider looking at this in a more OO way, and using 'tell don't ask'. So you would look at having a Brick class, which would know what its colour was, and its adjacent blocks. Then you would tell the first Block to explode, it would then know that if it was Orange (and maybe consider using Enums for this - not just numbers), then it would tell its adjacent Blocks to 'chain react' (or something like that), these blocks would then decide what to do (either explode in the case of an orange block - and call their adjacent blocks, or not in the case of a grey Block.
I know its quite different from what your doing currently, but will give you a better structured program hopefully.
I would imagine a method that would recursively get all touching cells of a similar color.
Then you can operate on that list (of all touching blocks) pretty easily and break all the ones are haven't been broken.
Also note that your getAdjentCell() method has side effects (it does the breaking) which isn't very intuitive based on the name.
// I agree with Matt that color (or type) should probably be an enum,
// or at least a class. int isn't very descriptive
public enum CellType { GRAY, RED, ORANGE }
public class Cell{
....
public final CellType type;
/**
* Recursively find all adjacent cells that have the same type as this one.
*/
public List<Cell> getTouchingSimilarCells() {
List<Cell> result = new ArrayList<Cell>();
result.add(this);
for (Cell c : getAdjecentCells()) {
if (c != null && c.type == this.type) {
result.addAll(c.getTouchingSimilarCells());
}
}
return result;
}
/**
* Get the 4 adjacent cells (above, below, left and right).<br/>
* NOTE: a cell may be null in the list if it does not exist.
*/
public List<Cell> getAdjecentCells() {
List<Cell> result = new ArrayList<Cell>();
result.add(cellBlock(this.getX() + 1, this.getY()));
result.add(cellBlock(this.getX() - 1, this.getY()));
result.add(cellBlock(this.getX(), this.getY() + 1));
result.add(cellBlock(this.getX(), this.getY() - 1));
return result;
}
}