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

2021/12/3

how to make my actor move slower/faster after touching something

spiu spiu

2021/12/3

#
So i have this frog that eats bugs but when it eats a certain kind of bug i want the frog to move slower/faster depending on the bug it ate. I only want this "power" to last a few seconds but i cant make the frog move at different speeds and also i dont know how to make it last a few seconds. This is inside the frog class
public int foundBug()
    {
        Actor bug = getOneObjectAtOffset(0, 0, Bug.class);
        if(bug != null) {
            Actor bug1 = getOneObjectAtOffset(0, 0, DoubleBug.class);
            Actor bug2 = getOneObjectAtOffset(0, 0, FastBug.class);
            Actor bug3 = getOneObjectAtOffset(0, 0, SlowBug.class);
            if(bug1!=null)
            {
                World myWorld = getWorld();
                getWorld().removeObject(bug1);
                return 1;
                
            }
            if(bug2!=null)
            {
                World myWorld = getWorld();
                getWorld().removeObject(bug2);
                return 2;
            }
            if(bug3!=null)
            {
                World myWorld = getWorld();
                getWorld().removeObject(bug2);
                return 3;
            }
            return 0;
        }
        else {
            return -1;
        }
    }
and it returns the int to my level class
public void act()
    {
        if(frog.foundBug()==1)
        {
            
        }
        if(frog.foundBug()==2)
        {
            frog.setSpeed(5);         
        }
        if(frog.foundBug()==3)
        {
            frog.setSpeed(1);
        }
        else if (frog.foundBug()==0)
        {
            frog.speed=3;
        }
}
danpost danpost

2021/12/3

#
In foundBug method, you do not need lines 5, 6 and 7; nor do you need 2 sets of 3 if statements (one in foundBug and one in act). With an int timer:
private int speedTimer;
in your frog class, the following should suffice:
public void foundBug()
{
    Actor bug = getOneObjectAtOffset(0, 0, Bug.class);
    if (bug == null) return;
    speedTimer = 60; // adjust duration of modified speed as needed
    getWorld().removeObject(bug);
    if (bug instanceof SlowBug) speed = 1;
    else if (bug instanceof DoubleBug) speed = 2;
    else if (bug instanceof FastBug) speed = 5;
    else speed = 3;
}
with the following in act before the bug eating:
if (speedTimer > 0 && --speedTimer == 0) speed = 3;
spiu spiu

2021/12/3

#
Thanks for responding. I added what you suggested and i changed a few things and now the frog doesnt move at all :( heres my code
import greenfoot.*;  

public class Frog extends Actor
{
    private int bugsEaten;
    public int x,y;
    protected int speed=3;
    private int speedTimer;
    private SimpleTimer time = new SimpleTimer();
    
    public Frog(){
        bugsEaten=0;
        speed=3;
    }
    
    public void act(int speed)
    {    
        if(foundBug()){
            if (speedTimer > 0 && --speedTimer == 0){
            speed = 3;
            }
            
            eatBug();
        }
        else{
            speed=3;
            moveAround(speed);
        }
    }
    
    public void moveAround(int speed)
    {
        if (Greenfoot.isKeyDown("left"))
        {
            x=getX()-speed;
            setLocation(x,getY());
            
        }
        if (Greenfoot.isKeyDown("right"))
        {
            setLocation(getX() + speed, getY());
        }
        if (Greenfoot.isKeyDown("down"))
        {
            setLocation(getX(), getY()+speed);
        }
        if (Greenfoot.isKeyDown("up"))
        {
            setLocation(getX(), getY() - speed);
        }
    }
    
    public boolean founddBug()
    {
        Actor bug = getOneObjectAtOffset(0, 0, Bug.class);
        if(bug != null) {
            return true;
        }
        else
        {
            return false;
        }
    }
    
    public boolean foundBug()
    {
        Actor bug = getOneObjectAtOffset(0, 0, Bug.class);
        if (bug == null) return false;
        speedTimer = 10;
        getWorld().removeObject(bug);
        if (bug instanceof SlowBug) {
            speed = -1;
        }
        else if (bug instanceof DoubleBug) 
            speed = 2;
        else if (bug instanceof FastBug){ 
            speed = 9;
        }
        else{ 
            speed = 3;
        }
        return true;
    }
    
    public void eatBug()
    {
        Actor bug = getOneObjectAtOffset(0, 0, Bug.class);
        if(bug != null) {
            World myWorld = getWorld();
            getWorld().removeObject(bug);
            Level level = (Level)myWorld;
            ScoreBoard score = level.getScore();
            score.addScore(1);
        }
    }
    
    public int getBugsEaten()
    {
        return bugsEaten;
    }
    
    public boolean die()
    {
        if(isTouching(Bird.class))
        {
            return true;
        }
        if(isTouching(Snake.class))
        {
            return true;
        }
        
        return false;
    }
    
    public void setSpeed(int speed)
    {
        this.speed=speed;
    }
}
danpost danpost

2021/12/3

#
Swap lines 27 and 28.
Spock47 Spock47

2021/12/4

#
I think additionally to the most important point danpost mentioned (no. 1), there is something off with the current act method:
        if(foundBug()){
            if (speedTimer > 0 && --speedTimer == 0){
                speed = 3;
            }
             
            eatBug();
        }
2. In the foundBug method, the bug gets already removed from the world, so when calling the eatBug method the bug is not there anymore to be eaten. I assume that your score currently only increases, if you touch two bugs at the same time (because foundBug removes one bug, so eatBug only rewards a score point, if there is another bug). 3. The speedTimer mechanism (counting down) is also only called in the moment, where a bug is found: So, foundBug finds a bug, sets the speedTimer at 10, then the inner if reduces the speedTimer to 9, but after that the inner if will never be called again (unless another bug is found, in which case the speedTimer will be reset to 10 before the inner if is called). So, I guess the speedTimer will always be at 9 or 10 (or 0 at the start). 4. Your act method has a parameter, but the act method that Greenfoot will call, does not have a parameter, so it will not call your act method. Possible solution: 1. In foundBug, replace line 70 (removing the bug) with "eatBug();" 2. Replace the act method with:
    public void act()
    {    
        foundBug();
        if (speedTimer > 0 && --speedTimer == 0) {
            speed = 3;
        }
        moveAround(speed);
    }
(3. Change the return type of foundBug to void, if you want.) Additional note: The moveAround method currently has a parameter "speed", too. But you already have an attribute "protected int speed". You can use the attribute, so you don't have to give the speed as a parameter to the method. Live long and prosper, Spock47
danpost danpost

2021/12/4

#
@Spock47, good catch on point #4 (I did not notice that). I think the order of operations in the act method should be reversed; that is, move first, run timer next, and eat last. All in all, without the act method in the level class, the frog class should be like this:
import greenfoot.*;

public class Frog extends Actor
{
    private int speed = 3;
    private int speedTimer;
    private int bugsEaten;
    
    public void act()
    {
        moveAround();
        runSpeedTimer();
        eatBug();
    }
    
    private void moveAround()
    {
        int dx = 0, dy = 0;
        if (Greenfoot.isKeyDown("left")) dx--;
        if (Greenfoot.isKeyDown("right")) dx++;
        if (Greenfoot.isKeyDown("up")) dy--;
        if (Greenfoot.isKeyDown("down")) dy++;
        setLocation(getX()+dx*speed, getY()+dy*speed);
    }
    
    private void runSpeedTimer()
    {
        if (speedTimer > 0 && --speedTimer == 0) speed = 3;
    }
    
    private void eatBug()
    {
        Actor bug = getOneObjectAtOffset(0, 0, Bug.class);
        if (bug == null) return;
        speedTimer = 60; // adjust duration of modified speed as needed
        getWorld().removeObject(bug);
        bugsEaten++;
        if (bug instanceof SlowBug) speed = 1;
        else if (bug instanceof DoubleBug) speed = 2;
        else if (bug instanceof FastBug) speed = 5;
        else speed = 3;
    }
    
    public int getBugsEaten()
    {
        return bugsEaten;
    }
}
danpost danpost

2021/12/4

#
The only issue that may be apparent is that the speed when moving diagonally is increased by about 40% because the frog is actually moving speed along both axes instead of along one vector. Even if you just moved along the diagonal direction by the speed value, it would not move at consistent speeds as when moving along one axis alone. This effect is more pronounced at slower speeds. You might consider using a smooth moving system to control the movement of the frog. My Smooth Mover Demo contains two different helper classes in that regard -- the one provided by greenfoot, which you can import directly, and the one I created, which you would need to download to use.
spiu spiu

2021/12/4

#
Hi! Thank you both, the frog now moves at different speeds thank you so much. I didn't mention it before but the DoubleBug actually gives double points when its eaten lol. This is how the code looks like with the modifications you made
import greenfoot.*;  

public class Frog extends Actor
{
    public int speed=3;
    private int speedTimer;

    public void act()
    {    
        moveAround();
        runSpeedTimer();
        eatBug();
    }
    
    public void moveAround()
    {
        int dx=0, dy=0;
        if (Greenfoot.isKeyDown("left"))
        {
            dx--;
            
        }
        if (Greenfoot.isKeyDown("right"))
        {
            dx++;
        }
        if (Greenfoot.isKeyDown("down"))
        {
            dy++;
        }
        if (Greenfoot.isKeyDown("up"))
        {
            dy--;
        }
        
        setLocation(getX()+dx*speed, getY()+dy*speed);
    }
    
    private void runSpeedTimer()
    {
        if(speedTimer>0 && --speedTimer==0)
            speed=3;
    }
    
    public void eatBug()
    {
        World myWorld = getWorld();
        Level level = (Level)myWorld;
        
        Actor bug = getOneObjectAtOffset(0, 0, Bug.class);
        if(bug == null) return;
        speedTimer=100;
        getWorld().removeObject(bug);
        if(bug instanceof SlowBug) speed=1;
        else if(bug instanceof DoubleBug){
           ScoreBoard score = level.getScore();
           score.addScore(2);
        }
        else if(bug instanceof FastBug) speed=5;
        else speed=3;
        
        
        ScoreBoard score = level.getScore();
        score.addScore(1);
        
    }
    
    public boolean die()
    {
        if(isTouching(Bird.class))
        {
            return true;
        }
        if(isTouching(Snake.class))
        {
            return true;
        }
        
        return false;
    }
    
}
Its working good :) thank you again
You need to login to post a reply.