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

2024/5/21

How to animate my character ?

Nordrasil Nordrasil

2024/5/21

#
Hello I'm recreating the Mario Bros game. I would like to animate my Mario character by alternating two images when I press the right key and two other images when I press the left key. But I can't animate it. That is to say that when I press the right key, there is only an image displayed. When I press the left key, there is only one image displayed. Thanks in advance to anyone who finds my error.
    private void checkPress()
    {
        if (Greenfoot.isKeyDown("right")) 
        {
            setImage(image1);
            setLocation(getX() + speed, getY());
            checkObstacle();
            animationRight();
        }
        if (Greenfoot.isKeyDown("left")) 
        {
            setImage(image2);
            setLocation(getX() - speed, getY());
            checkObstacle();
            animationLeft();
        }
        if (Greenfoot.isKeyDown("up"))
        {
            jump();
        }
    }
    
    public void animationRight()
    {
        if (getImage() == image1) 
        {
            setImage(image3);
        }
        else
        {
            setImage(image1);
        }
    }
    public void animationLeft()
    {
        if (getImage() == image2) 
        {
            setImage(image4);
        }
        else
        {
            setImage(image2);
        }  
    }
danpost danpost

2024/5/23

#
Remove lines 5 and 12. They are pre-setting the image every act step a "left" or "right" key is down.
Nordrasil Nordrasil

2024/5/23

#
It doesn't work. Now my character only uses the image 1.
danpost danpost

2024/5/24

#
Nordrasil wrote...
It doesn't work. Now my character only uses the image 1.
Please provide the entire code of the class (from imports to final squiggly bracket) to check.
Nordrasil Nordrasil

2024/5/24

#
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.util.List;
/**
 * Write a description of class Mario1 here.
 * 
 * @author Sarah Maria Ghanem 
 * @version (a version number or a date)
 */
public class Mario extends Actor
{
    private GreenfootImage image1;
    private GreenfootImage image2;
    private GreenfootImage image3;
    private GreenfootImage image4;
    private int speed = 4;
    private int vSpeed = 0;
    private int acceleration = 2;
    private int jumpStrength = 3;
    public Mario()
    {
        image1 = new GreenfootImage("marioR1.png");
        image2 = new GreenfootImage("marioL1.png");
        image3 = new GreenfootImage("marioR2.png");
        image4 = new GreenfootImage("marioL2.png");
        setImage(image1);
    }
    
    /**
     * Act - do whatever the Mario1 wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public void act()
    {
        checkPress();
        checkObstacle();
        checkFall();
        checkCollision();
        detection();
        animationLeft();
        animationRight();
    }  
    
    private void checkPress()
    {
        if (Greenfoot.isKeyDown("right")) 
        {
            setLocation(getX() + speed, getY());
            checkObstacle();
            animationRight();
        }
        if (Greenfoot.isKeyDown("left")) 
        {
            setLocation(getX() - speed, getY());
            checkObstacle();
            animationLeft();
        }
        if (Greenfoot.isKeyDown("up"))
        {
            jump();
        }
    }
    
    public void animationRight()
    {
        if (getImage() == image1) 
        {
            setImage(image3);
        }
        else
        {
            setImage(image1);
        }
    }
    
    public void animationLeft()
    {
        if (getImage() == image2) 
        {
            setImage(image4);
        }
        else
        {
            setImage(image2);
        }  
    }
    
    public void checkObstacle()
    {
        // check above the actor
        while (getOneObjectAtOffset(0, -getImage().getHeight()/2-1, Solid.class) != null) 
        {
            setLocation(getX(), getY()+1);
        }
        // check to left of actor
        while (getOneObjectAtOffset(getImage().getWidth()/2+1, 0, Solid.class) != null)
        {
            setLocation(getX()-1, getY());
        }
        // check to right of actor
        while (getOneObjectAtOffset(-getImage().getWidth()/2-1, 0, Solid.class) != null)
        {
            setLocation(getX()+1, getY());
        }
    }
    
    public void jump()
    {
        vSpeed = -jumpStrength;
        fall();
    }
    
    public void checkFall()
    {
        if(onSolid()) {
            vSpeed= 0;
        }
        else if (onPlateform()) {
            vSpeed= 0;
        }
        else {
            fall();
            if (getY() == 0)
            {
                Greenfoot.stop();
            }
        }
    } 
    
    public boolean onEnemies()
    {
        Actor under = getOneObjectAtOffset(getImage().getWidth()/2, getImage().getHeight()/2, Enemies.class);
        if( under != null)
        {
            return true;
        } else {
            return false;
        }
    }
    
    public void detection()
    {
        int distSautX = 0;
        int distSautY = 20;
        int w = getImage().getWidth()/2;
        int h = getImage().getHeight()/2;
        
        List<Enemies> myListEnemies=getWorld().getObjects(Enemies.class);
        
        for (Enemies myEnemy:myListEnemies)
        {
            if ((getX()> myEnemy.getX()- myEnemy.getImage().getWidth()/2 - distSautX - w) && (getX() < myEnemy.getX() + myEnemy.getImage().getWidth()/2 + distSautX + w))
            {
                if(getY() < myEnemy.getY() + myEnemy.getImage().getHeight()/2 + distSautY - h)
                {
                    getWorld().removeObject(myEnemy);
                    break;
                }
                //if(getY() >= myEnemy.getY() - myEnemy.getImage().getHeight()/2)
                //{
                //    getWorld().removeObject(this);
                //    break;
                //}
            }
        }
    }

    public boolean onSolid() 
    {
        Actor under = getOneObjectAtOffset(0, getImage().getHeight() / 2, 
        Solid.class);
        return under != null;
    }
    
    public boolean onPlateform()
    {
        Actor under = getOneObjectAtOffset(0, getImage().getHeight() / 2, 
        Plateform.class);
        return under != null;
    }
    
    private void fall()
    {
        setLocation(getX(), getY() + vSpeed);
        if(vSpeed < 10)
        {
            vSpeed = vSpeed + acceleration;
        }
    }
    
    public void checkCollision()
    {
        if (isTouching(Coin.class)) 
        {
            removeTouching(Coin.class);
            World1 world1 = (World1)getWorld();
            world1.addScore(1);
        }
        if (isTouching(GMushroom.class))
        {
            removeTouching(GMushroom.class);
            World1 world1 = (World1)getWorld();
            world1.addLife(1); 
        }
        if (isTouching(RMushroom.class))
        {
            removeTouching(RMushroom.class);
            World1 world1 = (World1)getWorld();
        }
        if ( isTouching(Enemies.class) ) 
        {
            World1 world1 = (World1)getWorld();
            world1.addLife(-1); 
        }
    }    
}
Nordrasil Nordrasil

2024/5/24

#
Here is the entire code of Mario class
Nordrasil Nordrasil

2024/5/24

#
Thank you I finally found my mistake. I just had to remove lines 39 and 40. But I have one last question to ask you. Is there a way to change the number of images per second?
danpost danpost

2024/5/25

#
Nordrasil wrote...
Is there a way to change the number of images per second?
You will need an int field to perform the duty of counting out full cycles of images:
private int animTimer;
Let us say you wanted each image to last for approximate 1/6 of a second (completing 3 cycles per second). That would be 10 act steps per image; so, the limit for the timer will only be 20 (only 2 images per animation set). You will use something like the following:
public void animationRight()
{
    animTimer = (animTimer+1)%20;
    setImage(animTimer/10 == 0 ? image1 : image3);
}
Unfortunately, this creates another problem. If both "left" and "right" keys are down, the animation speed will double. To prevent that, there can only be one call per act to animate. Therefore, I suggest the following:
private void checkPress() {
    int dx = 0;
    if (Greenfoot.isKeyDown("left")) dx--;
    if (Greenfoot.isKeyDown("right")) dx++;
    if (dx != 0) {
        setLocation(getX()+dx*speed, getY());
        checkObstacles();
        animate(dx);
    }
}

private void animate(int dir) {
    animTimer = (animTimer+1)%20;
    if (dir > 0) setImage(animTimer/10 == 0 ? image1 : image3);
    else setImage(animTimer/10 == 0 ? image2 : image4);
}
Nordrasil Nordrasil

2024/5/25

#
Thank you a lot for your help danpost.
You need to login to post a reply.