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

2017/2/14

Sound file playing too early... what do I do?

PJaymz PJaymz

2017/2/14

#
So I'm doing my IB Computer Science IA and working on code for a quiz game about music theory. I'm going pretty easy, but am having a big problem. There is a world for each question (9 questions) and a "hub" that has a welcome and start arrow that opens up one of the questions if pressed. If i am to open up the world with the question of identifying major chords, it looks like this (as of right now).
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class Qu1 here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class QuMaj extends World
{

    /**
     * Constructor for objects of class Qu1.
     * 
     */
    public QuMaj()
    {    
        // Create a new world with 600x400 cells with a cell size of 1x1 pixels.
        super(800, 474, 1); 
        prepare();
    }

    public void prepare()
    {
        play();
    }

    public void play()
    {

        switch(Greenfoot.getRandomNumber(6))
        {
            case 0:  Greenfoot.playSound("Major Chord #1.mid"); break;
            case 1:  Greenfoot.playSound("Major Chord #2.mid"); break;
            case 2:  Greenfoot.playSound("Major Chord #3.mid"); break;
            case 3:  Greenfoot.playSound("Major Chord #4.mid"); break;
            case 4:  Greenfoot.playSound("Major Chord #5.mid"); break;
            case 5:  Greenfoot.playSound("Major Chord #6.mid"); break;
        }
    } 
}

This works fine, except that when I open up the "QuizHub" world, it plays whatever chord will play in the major chord world, then playing it again when the world actually opens. What did I do wrong, and how can I fix it?? Here's the code for the QuizHub world as well (if it will help):
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.awt.Font;

/**
 * A Music Theory Quiz that tests the user's knowledge of chord qualities
 * in their inversions and root position.
 */
public class QuizHub extends World
{

    /**
     * Constructor for objects of class MyWorld.
     * 
     */
    public QuizHub()
    {    
        // Create a new world with 600x400 cells with a cell size of 1x1 pixels.
        super(800, 474, 1); 
        prepare();
    }

    /**
     * Prepare the world for the start of the program.
     * That is: create the initial objects and add them to the world.
     */
    private void prepare()
    {
        StartButton startbutton = new StartButton();
        addObject(startbutton,747,432);
        startbutton.setLocation(757,432);
        addObject(new Text(), 393, 231);
    }
}

And here's the code for the StartButton class (it is set to open the major chord world so that I could test its functionality):
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class StartButton here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class StartButton extends Actor
{
    World[] quList = {new QuMaj(),new QuMin(), new QuAug(), new QuDim(), new QuMaj7(), new QuMin7(), 
        new QuDom7(),new QuHDim7(), new QuDim7()};

            /**
             * Act - do whatever the StartButton wants to do. This method is called whenever
             * the 'Act' or 'Run' button gets pressed in the environment.
             */
    public void act() 
    {
        if (Greenfoot.mouseClicked(this))
        {
            Greenfoot.setWorld(new QuMaj());
        }
    }    
}
And sorry for the lack of description in the class description, I usually wait until I have clean code to insert it. Thanks!
davmac davmac

2017/2/14

#
I guess that the problem is this line, in StartButton:
    World[] quList = {new QuMaj(),new QuMin(), new QuAug(), new QuDim(), new QuMaj7(), new QuMin7(), 
        new QuDom7(),new QuHDim7(), new QuDim7()};
It creates one of each of the worlds, which (at least in the case of QuMaj) will cause their sound to play. It seems like you don't actually need that line, so perhaps just remove it.
PJaymz PJaymz

2017/2/15

#
davmac wrote...
I guess that the problem is this line, in StartButton:
    World[] quList = {new QuMaj(),new QuMin(), new QuAug(), new QuDim(), new QuMaj7(), new QuMin7(), 
        new QuDom7(),new QuHDim7(), new QuDim7()};
It creates one of each of the worlds, which (at least in the case of QuMaj) will cause their sound to play. It seems like you don't actually need that line, so perhaps just remove it.
In the case of what I posted, it is indeed unnecessary. However, in my finished code I want the StartButton code to look more like this:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class StartButton here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class StartButton extends Actor
{
    World[] quList = {new QuMaj(),new QuMin(), new QuAug(), new QuDim(), new QuMaj7(), new QuMin7(), 
        new QuDom7(),new QuHDim7(), new QuDim7()};

            /**
             * Act - do whatever the StartButton wants to do. This method is called whenever
             * the 'Act' or 'Run' button gets pressed in the environment.
             */
    public void act() 
    {
        if (Greenfoot.mouseClicked(this))
        {
            Greenfoot.setWorld(quList[Greenfoot.getRandomNumber(10)]);
        }
    }    
}
This means I'd need the array. I mean I guess I could use a switch statement, but was hoping to use an array in order to show my teacher a wider understanding of coding knowledge, since I am already using a switch within the worlds of each question when choosing a midi file to play. Any tips? If it doesn't work I'll just do a switch statement when StartButton is clicked. -Would creating the array within the if statement maybe work?
davmac davmac

2017/2/15

#
Would creating the array within the if statement maybe work?
Your problem is that the sound is played when the world is constructed; specifically it is played in the play() method which is called from prepare() which is in turn called from the constructor (QuMaj()). If you create the array within the if statement then you just defer the issue to when the if statement runs. If each of your worlds plays a sound, then they will *all* play the sound at that time - include the QuMaj world, which will play its sound, even if it doesn't get selected. There are essentially two solutions:
  • Only create the world that you actually want to set active
  • Don't play the sound when creating the world - instead play it when the world is set active
The first solution would mean not using an array, and instead doing something like:
    public void act() 
    {
        if (Greenfoot.mouseClicked(this))
        {
            switch (Greenfoot.getRandomNumber(10)) {
            case 0:
                Greenfoot.setWorld(new QuMaj());
                break;
            case 1:
                Greenfoot.setWorld(new QuMin());
                break;
            // etc
            }        
        }
    }    
The second solution would likely have each world inherit from a common base class, something like:
class BaseWorld extends World
{
    public void setActive()
    {
        // Base implementation does nothing
    }
}
Your other worlds extend BaseWorld, so for QuMaj for example:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
 
public class QuMaj extends BaseWorld
{
 
    /**
     * Constructor for objects of class Qu1.
     * 
     */
    public QuMaj()
    {    
        // Create a new world with 600x400 cells with a cell size of 1x1 pixels.
        super(800, 474, 1); 
        prepare();
    }
 
    public void prepare()
    {
        // play(); - not anymore!
    }

    public void setActive()
    {
        // this overrides the implementation from BaseWorld:
        play();
    }
 
    public void play()
    {
 
        switch(Greenfoot.getRandomNumber(6))
        {
            case 0:  Greenfoot.playSound("Major Chord #1.mid"); break;
            case 1:  Greenfoot.playSound("Major Chord #2.mid"); break;
            case 2:  Greenfoot.playSound("Major Chord #3.mid"); break;
            case 3:  Greenfoot.playSound("Major Chord #4.mid"); break;
            case 4:  Greenfoot.playSound("Major Chord #5.mid"); break;
            case 5:  Greenfoot.playSound("Major Chord #6.mid"); break;
        }
    } 
}
Your StartButton act method then becomes:
    BaseWorld[] quList = {new QuMaj(),new QuMin(), new QuAug(), new QuDim(), new QuMaj7(), new QuMin7(), 
        new QuDom7(),new QuHDim7(), new QuDim7()};

    public void act() 
    {
        if (Greenfoot.mouseClicked(this))
        {
            BaseWorld world = quList[Greenfoot.getRandomNumber(10)];
            Greenfoot.setWorld(world);
            world.setActive();
        }
    }
You need to login to post a reply.