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

2018/2/28

Need help for my movement code

Kolyma Kolyma

2018/2/28

#
Hey guys, i created the movement code for my actor class "Mädchen". The problem is that it is always looking at the right edge of my world. Regardless of whether it runs to the right or to the left. How can I program it to look to the left when it runs to the left?
public class Mädchen extends Actor
{
    private GreenfootImage image1;
    private GreenfootImage image2;
    private GreenfootImage image3;
    private int imgTimer = 0;
    
    public Mädchen()
    {
        image1=new GreenfootImage("silhouette1.png");
        image2=new GreenfootImage("silhouette2.png");
        image3=new GreenfootImage("silhouette3.png");
        setImage(image1);
    }
    public void act()
    {
        move();
        switchImage();
        removeTouching(Apple.class);
        removeTouching(Banana.class);
        removeTouching(Lemon.class);
    }
    public void move()
    {
        if (Greenfoot.isKeyDown("right")) 
        {
            move(3);
        }
        if (Greenfoot.isKeyDown("left"))
        {
            move(-3);
        }
    }
    public void switchImage()
    {
        if (++imgTimer%10 != 0) return;
        if (getImage() == image1)
        {
            setImage(image2);
        }
        else
        {
        if (getImage() == image2)
        {
            setImage(image3);
        }
        else
        {
            setImage(image1);
        }
    }
    }
}
Yehuda Yehuda

2018/2/28

#
You can set a new image to the actor, which looks the same besides for the fact the it was mirrored. Greenfoot gives a method for mirroring images. mirrorHorizontally By you it will be more complicated since you have multiple images for moving in one direction. You'll have to mirror all of them and go through the same process for moving either right or left.
Kolyma Kolyma

2018/2/28

#
Thank you for your reply. I solved the problem by mirroring the images in Gimp and then inserting them into the code accordingly. Not very elegant, but I have achieved my goal.
public class Mädchen extends Actor
{
    private GreenfootImage image1;
    private GreenfootImage image2;
    private GreenfootImage image3;
    private GreenfootImage image4;
    private GreenfootImage image5;
    private GreenfootImage image6;
    private int imgTimer = 0;
    
    public Mädchen()
    {
        image1=new GreenfootImage("silhouette1.png");
        image2=new GreenfootImage("silhouette2.png");
        image3=new GreenfootImage("silhouette3.png");
        image4=new GreenfootImage("silhouette1_links.png");
        image5=new GreenfootImage("silhouette2_links.png");
        image6=new GreenfootImage("silhouette3_links.png");
        setImage(image1);
    }
    public void act()
    {
        move();
        removeTouching(Apple.class);
        removeTouching(Banana.class);
        removeTouching(Lemon.class);
    }
    public void move()
    {
        if (Greenfoot.isKeyDown("right")) 
        {
            move(5);
            if (++imgTimer%10 != 0) return;
        if (getImage() == image1)
        {
            setImage(image2);
        }
        else
        {
           if (getImage() == image2)
        {
            setImage(image3);
        }
        else
        {
            setImage(image1);
        }
        }
        }
        if (Greenfoot.isKeyDown("left"))
        {
            move(-5);
            if (++imgTimer%10 != 0) return;
        if (getImage() == image4)
        {
            setImage(image5);
        }
        else
        {
           if (getImage() == image5)
        {
            setImage(image6);
        }
        else
        {
            setImage(image4);
        }
        }
        }
    }
    
    
}
Maybe you could tell me how I could do that more efficiently?
Vercility Vercility

2018/2/28

#
idk, he legitimately explained how to do it and even posted the method api lol Mirror
Agent40 Agent40

2018/2/28

#
To make the code more efficient you could run a timer that only actives when a boolean value is set to true when a keypress occurs This would work more efficently in my mind and allow you use this code once. Variables:
private boolean Moving = false;
private int Timer = 0;
One time code:
if (Moving == true;)
{
      Timer = Timer + 1;
}
else
{
      Timer = 0;
}
Then for each Keypress:
if (Greenfoot.isKeyDown("right")) 
{
     Moving = true;
     if (Timer == 10)
     {
          setImage(Image1);
     }
     if (Timer == 20)
     {
          setImage(Image2);
     }
     if (Timer == 30)
     {
          setImage(Image3);
     }
     if (Timer == 40)
     {
          Timer = 0;
     }
}
else
{
     Moving = false;
}
danpost danpost

2018/3/1

#
Agent40 wrote...
To make the code more efficient you could run a timer that only actives when a boolean value is set to true when a keypress occurs This would work more efficently in my mind and allow you use this code once. << Code Omitted >>
That code can definitely be improved upon. The fact that the third image will show twice as long as the others while a key is down is an minor issue. I would like to address the general behavior of the animation. Consider what happens when the movement keys are released -- whatever image was showing will be the still image for the actor. It might be a different frame of the animation at various idle times. If the actor is in the middle of a step where the feet are separated, it would not look very good. I would consider a third set of animation images for when the actor is idle -- even if the set consists of only one image. Adding the third animation set will overload the Moving field suggested as there would be three things (animation sets) to consider instead of two. This may seem to complicate things as far as coding is concerned. However, by grouping the frames for each set and a little code manipulation, you could have something like this:
/* fields */
GreenfootImage[] animL = new GreenfootImage[3]; // left images
GreenfootImage[] animR = new GreenfootImage[3]; // right images
GreenfootImage[] animX = new GreenfootImage[2]; // idle images
GreenfootImage[] anim = animX; // current animation
int timer; // animation timer

/* in constructor */
animR[0] = new GreenfootImage("silhouette1.png");
animR[1] = new GreenfootImage("silhouette2.png");
animR[2] = new GreenfootImage("silhouette3.png");
animL[0] = new GreenfootImage("silhouette1_links.png");
animL[1] = new GreenfootImage("silhouette2_links.png");
animL[2] = new GreenfootImage("silhouette3_links.png");
animXR[0] = new GreenfootImage(animR[0]);
animXL[1] = new GreenfootImage(animL[0]);        
setImage(anim[0]);

/* in act (or method called by act) */
// determine which way to move (if at all)
int dx = 0;
if (Greenfoot.isKeyDown("right")) dx++;
if (Greenfoot.isKeyDown("left")) dx--;
// assume not moving (still)
GreenfootImage[] toAnim = anim; // in case already still
if (anim == animL) toAnim = animXL; else if (anim == animR) toAnim = animXR; // in case was not still
// determine what moving animation to use (if not still)
if (dx == 1) toAnim = animR; else if (dx == -1) toAnim = animL;
// control animation
if (toAnim != anim) // if changing animation
{
    // initialize animation
    anim = toAnim;
    setImage(anim[0]);
    timer = 0;
}
else // not changing animation
{
    // run animation
    timer = (timer+1)%(anim.length*5);
    if (timer%5 == 0) setImage(anim[timer/5]);
}
Agent40 Agent40

2018/3/1

#
danpost wrote...
Agent40 wrote...
To make the code more efficient you could run a timer that only actives when a boolean value is set to true when a keypress occurs This would work more efficently in my mind and allow you use this code once. << Code Omitted >>
That code can definitely be improved upon. The fact that the third image will show twice as long as the others while a key is down is an minor issue. I would like to address the general behavior of the animation. Consider what happens when the movement keys are released -- whatever image was showing will be the still image for the actor. It might be a different frame of the animation at various idle times. If the actor is in the middle of a step where the feet are separated, it would not look very good. I would consider a third set of animation images for when the actor is idle -- even if the set consists of only one image. Adding the third animation set will overload the Moving field suggested as there would be three things (animation sets) to consider instead of two. This may seem to complicate things as far as coding is concerned. However, by grouping the frames for each set and a little code manipulation, you could have something like this:
/* fields */
GreenfootImage[] animL = new GreenfootImage[3]; // left images
GreenfootImage[] animR = new GreenfootImage[3]; // right images
GreenfootImage[] animX = new GreenfootImage[2]; // idle images
GreenfootImage[] anim = animX; // current animation
int timer; // animation timer

/* in constructor */
animR[0] = new GreenfootImage("silhouette1.png");
animR[1] = new GreenfootImage("silhouette2.png");
animR[2] = new GreenfootImage("silhouette3.png");
animL[0] = new GreenfootImage("silhouette1_links.png");
animL[1] = new GreenfootImage("silhouette2_links.png");
animL[2] = new GreenfootImage("silhouette3_links.png");
animXR[0] = new GreenfootImage(animR[0]);
animXL[1] = new GreenfootImage(animL[0]);        
setImage(anim[0]);

/* in act (or method called by act) */
// determine which way to move (if at all)
int dx = 0;
if (Greenfoot.isKeyDown("right")) dx++;
if (Greenfoot.isKeyDown("left")) dx--;
// assume not moving (still)
GreenfootImage[] toAnim = anim; // in case already still
if (anim == animL) toAnim = animXL; else if (anim == animR) toAnim = animXR; // in case was not still
// determine what moving animation to use (if not still)
if (dx == 1) toAnim = animR; else if (dx == -1) toAnim = animL;
// control animation
if (toAnim != anim) // if changing animation
{
    // initialize animation
    anim = toAnim;
    setImage(anim[0]);
    timer = 0;
}
else // not changing animation
{
    // run animation
    timer = (timer+1)%(anim.length*5);
    if (timer%5 == 0) setImage(anim[timer/5]);
}
can agree, half my fault I didn't proof read as well as I should have, let me fix that now. Also I will admit that using an array to load images should always be used. nvm, can't edit the post
danpost danpost

2018/3/1

#
Agent40 wrote...
I will admit that using an array to load images should always be used.
If "loading the images" refers to setting one of multiple images of an actor and not to loading the fields with the images. Of course, with an abundance of images, you would want to change the filenames to facilitate loading the fields using a loop. At any rate, the arrays here are used (1) to group the images of each animation set; (2) to easily assign the current animation images; and (3) to iterate among the images easily.
danpost danpost

2018/3/1

#
I forgot to add a line in my code above. Insert the following at line 24:
move(5*dx);
Kolyma Kolyma

2018/3/1

#
@danpost Thank you for your detailed reply. I changed my code like you said. But now there is the error "cannot find symbol - variable animXR" and Greenfoot marks me line 15. Did I forgot something?
public class Mädchen extends Actor
{
    private GreenfootImage[] animL = new GreenfootImage[3]; //Bilder links
    private GreenfootImage[] animR = new GreenfootImage[3]; //Bilder rechts 
    private GreenfootImage[] animX = new GreenfootImage[2]; //inaktive Bilder 
    private GreenfootImage[] anim = animX; //momentane Animation
    private int timer; //Timer für die Animationen
    
    public Mädchen()
    {
        animR[0] = new GreenfootImage("silhouette1.png");
        animR[1] = new GreenfootImage("silhouette2.png");
        animR[2] = new GreenfootImage("silhouette3.png");
        animL[0] = new GreenfootImage("silhouette1_links.png");
        animL[1] = new GreenfootImage("silhouette2_links.png");
        animL[2] = new GreenfootImage("silhouette3_links.png");
        animXR[0] = new GreenfootImage(animR[0]);
        animXL[1] = new GreenfootImage(animL[0]);
        setImage(anim[0]);
    }
    public void act()
    {
        move();
        removeTouching(Apple.class);
        removeTouching(Banana.class);
        removeTouching(Lemon.class);
    }
    public void move()
    {
        int dx = 0;
        if (Greenfoot.isKeyDown("right")) dx++;
        if (Greenfoot.isKeyDown("left")) dx--;
        move(5*dx); 
        
        GreenfootImage[] toAnim = anim;
        
        if (anim == animL) toAnim = animXL; else if (anim == animR) toAnim = animXR;
        
        if (dx == 1) toAnim = animR; else if (dx == -1) toAnim = animL;
        
        if (toAnim != anim)
        {
            anim = toAnim;
            setImage(anim[0]);
            timer = 0;
        }
        else
        {
            timer = (timer+1)%(anim.length*5);
            if (timer%5 == 0) setImage(anim[timer/5]);
        }
    }
}
danpost danpost

2018/3/1

#
You did not miss anything -- I did. I was going back and forth between two ideas and did not make all adjustments in my final decision. Replace your lines 5 and 6 with the following:
private GreenfootImage[] animXR = new GreenfootImage[1]; //inaktive Bilder rechts
private GreenfootImage[] animXL = new GreenfootImage[1]; //inaktive Bilder links
private GreenfootImage[] anim = animXR; //momentane Animation
Then your line 18 should be:
animXL[0] = new GreenfootImage(animL[0]);
Kolyma Kolyma

2018/3/1

#
It worked now. Thank you so much!
PeterMuller PeterMuller

2018/3/2

#
Greenfoot is trash , it always crash Your tweeter Peter
You need to login to post a reply.