This site requires JavaScript, please enable it in your browser!
Greenfoot back
blair
blair wrote ...

2012/4/23

PLEASE HELP?

blair blair

2012/4/23

#
I am attempting to add directional gravity to object by using the left and right arrow keys. can some one explain what i need to add or if im doing anything wrong?
public class Body extends SmoothMover
{
    private static final double GRAVITY = 7.8;
    private static final Color defaultColor = new Color(255, 216, 0);

    private double mass;
    private int size;

    /**
     * Construct a Body with default size, mass, movement and color.
     */
    public Body()
    {
        this (20, 300, new Vector(0, 0.0), defaultColor);
    }

    /**
     * Construct a Body with a specified size, mass, movement and color.
     */
    public Body(int size, double mass, Vector movement, Color color)
    {
        this.mass = mass;
        this.size = size;
        addForce(movement);
        GreenfootImage image = new GreenfootImage (size, size);
        image.setColor (color);
        image.fillOval (0, 0, size-1, size-1);
        setImage (image);
    }

    /**
     * Act. That is: apply  the gravitation forces from
     * all other bodies around, and then move.
     */
    public void act() 
    {
        applyForces();
        move();
        bounceAtEdge();
        control();
    }

    /**
     * Check whether we have hit the edge of the universe. If so, bounce off it.
     */
    private void bounceAtEdge()
    {
        if (getX() == 0 || getX() == getWorld().getWidth()-1) {
            setLocation((double)getX(), (double)getY());
            getMovement().revertHorizontal();
            accelerate(0.9);
            changeColor();
        }
        else if (getY() == 0 || getY() == getWorld().getHeight()-1) {
            setLocation((double)getX(), (double)getY());
            getMovement().revertVertical();
            accelerate(0.9);
            changeColor();
        }
    }

    /**
     * Apply the forces of gravity from all other celestial bodies in this universe.
     */
    private void applyForces()
    {
        List<Body> bodies = (List<Body>) getWorld().getObjects(Body.class);

        for (Body body : bodies) 
        {
            if (body != this) 
            {
                applyGravity (body);
            }
        }

        // ensure that we don't get too fast: If the current speed is very fast, decelerate a bit.
        if (getSpeed() > 5) 
        {
            accelerate (0.9);  // acceleration with factor < 1 is actually slowing down.
        }
    }

    /**
     * Apply the gravity force of a given body to this one.
     */
    private void applyGravity(Body other)
    {
        double dx = other.getExactX() - this.getExactX();
        double dy = other.getExactY() - this.getExactY();
        Vector force = new Vector (dx, dy);
        double distance = Math.sqrt (dx*dx + dy*dy);
        double strength = GRAVITY * this.mass * other.mass / (distance * distance);
        double acceleration = strength / this.mass;
        force.setLength (acceleration);
        addForce (force);
    }

    /**
     * Return the mass of this body.
     */
    public double getMass()
    {
        return mass;
    }

    public void control()
    {
        Actor obstacle = getOneIntersectingObject(Obstacle.class);
        List<Body> bodies = (List<Body>) getWorld().getObjects(Body.class);
        if (Greenfoot.isKeyDown("left"))
        {           
           for (Body body : bodies) 
        {
            if (body != this) 
            {
                applyGravity (body);
            }
        }
        }
        
        
         if (Greenfoot.isKeyDown("right"))
        {           
            for (Body body : bodies) 
        {
            if (body != this) 
            {
                applyGravity (body);
            }
        }
        }
        
        
        if (obstacle != null)
        {
            changeColor();
        }
    }

    private void changeColor()
    {
        int x = Greenfoot.getRandomNumber(255);
        int y = Greenfoot.getRandomNumber(255);
        int z = Greenfoot.getRandomNumber(255);
        GreenfootImage image = new GreenfootImage (size, size);
        image.setColor (new Color(x,y,z));
        image.fillOval (0, 0, size-1, size-1);
        setImage (image);   
    }
    
}
danpost danpost

2012/4/23

#
One thing I see is that you have the same exact code for both the left and right keys. As is, it appears that holding down one of the keys will apply normal gravity from other bodies (directional to the bodies; I do not think that is what you were wanting), while holding down both keys at the same time will double the normal gravity from other bodies. You will have to add those forces in seperately, so that if both keys are down, the forces cancel each other out.
blair blair

2012/4/23

#
Well the goal is when the left key is pressed it applies a small force to all bodies in the left direction and then to the right when the right arrow key is pressed. any idea on how to implement a code that can do this?
danpost danpost

2012/4/23

#
The easiest way, I think, would be to break up the applyGravity(Body other) method into two methods
private void applyGravity(Body other)
{
    double otherX = other.getExactX();
    double otherY = other.getExactY();
    double otherM = other.mass;
    applyGravity(otherX, otherY, otherM)
}

private void applyGravity(double x, double y, double m)
{
    double dx = x - this.getExactX();
    double dy = y - this.getExactY();
    Vector force = new Vector (dx, dy);
    double distance = Math.sqrt (dx*dx + dy*dy);
    double strength = GRAVITY * this.mass * m / (distance * distance);
    double acceleration = strength / this.mass;
    force.setLength (acceleration);
    addForce (force);
}
Now, in applyForces(), you can check for keystrokes, and, if found, use applyGravity(x, 0, m) to add the force (x would probably be zero for left and getWorld().getWidth() - 1 for right; m would be of your choosing).
ttamasu ttamasu

2012/4/25

#
It sounds like you are using the newton's lab example, you need to just add a force to each body and then just run newton's gravity formula (applyGravity) on the new bodies. I would probably do the following: if (Greenfoot.isKeyDown ("left")){ this.addForce(new Vector(180,0.1)); } else if (Greenfoot.isKeyDown("right")){ this.addForce(new Vector(0,0.1)); }
blair blair

2012/4/26

#
yes that worked thank you!. just one more question how would you make the block blink (toggle) when you have a body hit them. I got the block to turn on and off if an object hits them, but i am required to make it so when a body hits a block it flashes on and off and also plays a sound periodically.
public class Obstacle extends Actor
{
    private String sound;
    private boolean touched = false;
    private boolean toggledOn = false;
    
    /**
     * Create an obstacle with an associated sound file.
     */
    public Obstacle(String soundFile)
    {
        sound = soundFile;
    }
    
    /**
     * Each act cycle, check whether we were hit. If we were, play our sound.
     */
    public void act() 
    {
        checkToggle();
    }    
    
    private void checkToggle()
    {
        if (!touched && isTouching())
        {
            touched = true;
            toggledOn = !toggledOn;
            if (toggledOn)
            {
                setImage ("block-light.png");
                Greenfoot.playSound(sound);
            }
            else
            {
                setImage ("block.png");
        }
    }
        if (touched && !isTouching()) touched = false;
        
    }    
    public void playSound()
    {
        Greenfoot.playSound(sound);
    }
    
    private boolean isTouching()
    {
        return (getOneIntersectingObject(Body.class) !=null);
    }
}
ttamasu ttamasu

2012/4/26

#
 // untested suggested code
    private static final playSoundTime = 100;
    private  counter = playSoundTime:
......
  
// pull inner if statment out and add counter.
  if (!touched && isTouching()) 
    touched = true;
  else if (touched && !isTouching())
  {
      touched = false;
      toggleOn = !ToggleOn;
       }

  if (toggleOn)
      {
         setImage("block-light.png");
         if (counter++  > playSoundTime)
         {
                 counter = 0;
                 Greenfoot.playSound(sound);
        }
     }
      else
         setImage("block.png");

If I understand your logic correctly then I think you got the outer most if statement reversed. You want to check the toggle after the body is no longer touching the obstacle. Otherwise you will keep on fliping the toggle. I think if you did it the way I did above it should work if you want to hear the sound once.... If you want to make it play periodically, you need to pull out the if (toggleOn) if statement out (at the same level as the other if staments) and implement a counter . so I resubmitted my orginal test code (meaning that it has never been compiled) up . See if it works. -- Takashi
You need to login to post a reply.