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.
Related
I'm trying to make a pong game using JavaFX and I've decided to use Point2D for the paddle and ball positions.
I created this method to check for wall collisions
public void checkWallCollision(){
boolean ballHitBottom = posBall.getY() > 500;
boolean ballHitTop = posBall.getY() < 50;
boolean ballHitLeft = posBall.getX() < 0;
boolean ballHitRight = posBall.getX() > 725;
if (ballHitTop || ballHitBottom){
ballDirVector = ballDirVector.multiply(-1);
}
if(ballHitLeft || ballHitRight){
ballDirVector = ballDirVector.multiply(-1);
}
}
But with a Point2D object like that, I can't just multiply it like that. I need the angle to be reflected. I guess another thing I could show to help is how I launch the ball. In this method I do have the angle, but I'm not sure what way I should go about accessing it.
public void launchBall(){
// Launch the ball
boolean ballDirection = random.nextBoolean();
// bound to an acute angle on start
double ballAngle = Constants._PADDLE_ANGLES[random.nextInt(5) + 1];
if (ballDirection){
ballAngle *= -1;
}
ballSpeed = Constants._BallStartSpeed;
ballDirVector = new Point2D(Math.cos(ballAngle), Math.sin(ballAngle));
}
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.
I have a object(named frame) on screen,it will move either left or right according to where I move my finger.
public void handleSwipeInput() {
if (MyInputProcessor.isTouchDown) {
float movedir = MyInputProcessor.dist > 0 ? 1 : -1;
float speed = 30;
float actualSpeed = Math.abs(MyInputProcessor.dist) >= speed ? speed : Math.abs(MyInputProcessor.dist);
if (movedir > 0) {
frame.setX(frame.getX() + actualSpeed+2);
MyInputProcessor.dist -= actualSpeed;
} else {
frame.setX(frame.getX() - actualSpeed-2);
MyInputProcessor.dist += actualSpeed;
}
}
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
dist+=screenX-start;
start=screenX;
isTouchDragged=true;
return false;
}
In update() method:
if (MyInputProcessor.isTouchDown && Math.abs(MyInputProcessor.dist)>5.0f)
handleSwipeInput();
This works perfect,and I am adding an array of objects(named circles) below the frame object while moving,so that,those array of elements also moves along with my finger.
So I set positions of circles[] sequentially below frame object:
if(parts.size()!=0)
{
for (int i = 0; i <parts.size(); i++){
if(parts.get(i) instanceof Block){
circles[i].setIndex(parts.get(i).getIndex()) ;
circles[i].setPosition(frame.getX()-frame.getRadius(),
(frame.getY()-(frame.getRadius()*3))-(60*i));
}
This also works fine.Both frame and below objects gets a feel that they are moving along with my finger,and frame objects with mentioned speed.
Now I want to create an effect like,each of the circles objects should follow frame object with some delay,according to their positions.
So that it will appear like a smooth snake movement(As in snake vs block game).
For this,I tried to make use of tweens.
Tween.to(circles[0], Accessor.POS_XY,0.05f)
.target(circles[0].getX()+10,circles[0].getY())
.ease(TweenEquations.easeInSine)
.start(tweenManager);
Tween.to(circles[1], Accessor.POS_XY,0.05f)
.target(circles[1].getX()+20,circles[1].getY())
.ease(TweenEquations.easeInSine)
.start(tweenManager);
Tween.to(circles[2], Accessor.POS_XY,0.05f)
.target(circles[2].getX()+30,circles[2].getY())
.ease(TweenEquations.easeInSine)
.start(tweenManager);
But I am not able to work the logic out with tweens.
Confused of implementing a sequential delay for each circle object,according to the touch input ,with tweens.
I have created an array which contain sequential values to control the movement of circles to look like a snake.
private float delayValue[]={0.03f,0.04f,0.05f,0.06f,0.07f,0.08f,0.09f,0.10f};
Simple tween I used:
if (movedir > 0) {
frame.setX(frame.getX() + actualSpeed);
MyInputProcessor.dist -= actualSpeed;
tweenManager.killAll();
for (int i = 0; i < parts.size(); i++) {
Tween.to(circles[i], Accessor.POS_XY, delayValue[i])
.target(frame.getX() - frame.getRadius(), circles[i].getY()).start(tweenManager);
}
} else if (movedir < 0) {
frame.setX(frame.getX() - actualSpeed);
MyInputProcessor.dist += actualSpeed;
tweenManager.killAll();
for (int i = 0; i < parts.size(); i++) {
Tween.to(circles[i], Accessor.POS_XY, delayValue[i])
.target(frame.getX() - frame.getRadius(),
circles[i].getY()).start(tweenManager);
}
setting positions:
if(parts.size()!=0)
{
for (int i = 0; i <parts.size(); i++){
if(parts.get(i) instanceof Block){
circles[i].setIndex(parts.get(i).getIndex()) ;
circles[i].setPosition(circles[i].getX(), (frame.getY() -
(frame.getRadius() * 3)) - (60 * i));
}
In this way,I managed to make smooth movement as per my requirement.(Though it is not much fine as snake vs block game,but meets my requirement).
I'm working on a program that displays circles colliding with the wall and with themselves.
I'm having trouble with the method that will compensate for collisions.
public class bouncyFX extends Application {
public ArrayList<Ball> arr = new ArrayList<Ball>();
public static void main(String[] args) {
launch(args);
}
static Pane pane;
#Override
public void start(final Stage primaryStage) {
pane = new Pane();
final Scene scene = new Scene(pane, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
pane.setOnMouseClicked(new EventHandler<MouseEvent>() {
public void handle(final MouseEvent event) {
final Ball ball = new Ball(event.getX(), event.getY(), 40, Color.AQUA);
ball.circle.relocate(event.getX(), event.getY());
pane.getChildren().addAll(ball.circle);
arr.add(ball);
final Bounds bounds = pane.getBoundsInLocal();
final Timeline loop = new Timeline(new KeyFrame(Duration.millis(10), new EventHandler<ActionEvent>() {
double deltaX = ball.ballDeltaX;
double deltaY = ball.ballDeltaY;
public void handle(final ActionEvent event) {
ball.circle.setLayoutX(ball.circle.getLayoutX() + deltaX);
ball.circle.setLayoutY(ball.circle.getLayoutY() + deltaY);
final boolean atRightBorder = ball.circle.getLayoutX() >= (bounds.getMaxX()-ball.circle.getRadius());
final boolean atLeftBorder = ball.circle.getLayoutX() <= (bounds.getMinX()+ball.circle.getRadius());
final boolean atBottomBorder = ball.circle.getLayoutY() >= (bounds.getMaxY()-ball.circle.getRadius());
final boolean atTopBorder = ball.circle.getLayoutY() <= (bounds.getMinY()+ball.circle.getRadius());
if(atRightBorder || atLeftBorder)
deltaX *= -1;
if(atBottomBorder || atTopBorder)
deltaY *= -1;
for(int i = 0; i<arr.size(); i++){
for(int j = i+1; j<arr.size()-1; j++){
arr.get(i).collisionMagnitued(arr.get(j));
}
}
}
}));
loop.setCycleCount(Timeline.INDEFINITE);
loop.play();
}
});
}
class Ball{
public Circle circle;
public double ballDeltaX = 3;
public double ballDeltaY = 3;
public void AddBall(Ball b){
arr.add(b);
}
public Ball(double X, double Y, double Rad, Color color) {
circle = new Circle(X, Y, Rad);
circle.setFill(color);
}
private boolean defineCollision(Ball b){
double xd = this.circle.getLayoutX() - b.circle.getLayoutX();
double yd = this.circle.getLayoutY() - b.circle.getLayoutY();
double sumRad = this.circle.getRadius() + b.circle.getRadius();
double squareRad = Math.pow(sumRad, 2);
double distSquare = Math.pow(xd, 2) + Math.pow(yd, 2);
if(distSquare <= squareRad){
return true;
}return false;
}
public void collisionMagnitued(Ball b){
if(this.defineCollision(b)){
double tempDeltaX = ballDeltaX;
double tempDeltaY = ballDeltaY;
if((this.ballDeltaX < 0 && b.ballDeltaX > 0) || (this.ballDeltaX >0 && b.ballDeltaX <0)){
this.ballDeltaX *= -this.ballDeltaX;
b.ballDeltaX *= -b.ballDeltaX;
System.out.println("tredje");
}
if((this.ballDeltaY < 0 && b.ballDeltaY > 0) || (this.ballDeltaY > 0 && b.ballDeltaY < 0)){
this.ballDeltaY *= -this.ballDeltaY;
b.ballDeltaY *= -b.ballDeltaY;
System.out.println("fjärde");
}
else{
System.out.println("Knull");
this.ballDeltaX *= -1;
b.ballDeltaX *= -1;
}
}
}
}
}
The Balls (or circles) are created and are bouncing against the Bounds as expected.
The Collision detection method works as I'm getting print statements inside the last method. However, it seems that there's something wrong with either my ArrayList not being filled with objects or the method trying to compare the parameter Ball and the Ball that calls the method.
Am I way off? Not sure how I'm suppossed to go forth from here.
I see a few issues with your logic:
The first problem is that when the balls "bounce" off the boundaries of the pane, you don't change their ballDeltaX or ballDeltaY values (you just change a local value in the animation loop and use the local value to update the position). So the first time two balls collide, both of their ballDeltaX and ballDeltaY values are equal to +3 (the initial value), which may not represent the actual direction the animation loop is moving them in. In fact, you never actually use any updated values of ballDeltaX or ballDeltaY to compute the new positions; you get the initial values of those variables, copy them into deltaX and deltaY, and then just compute the new positions using deltaX and deltaY. So if you change ballDeltaX and ballDeltaY, the animation loop never sees the change.
The for loops look wrong to me; I don't think they compare the last two elements of the list. (When i = arr.size()-2 in the penultimate iteration of the outer loop, your inner loop is for (int j = arr.size() - 1; j < arr.size() -1; j++) {...} which of course never iterates.) I think you want the bounding conditions to be i < arr.size() - 1 and j < arr.size(), i.e. the other way around.
And then your if/else structure in collisionMagnitued(...) is probably not exactly what you want. I'm not sure what you're trying to implement there, but the else clause only kicks in if the second if is false, and no matter what happens in the first if.
Finally, you are starting a new animation on each mouse click. So, for example, if you have three balls bouncing around, you have three animation loops running, each of which is updating values when the balls collide. You need to start just one loop; it shouldn't do any harm if it refers to an empty list.
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);
}