Wednesday, October 19, 2011

Wednesday Post 4

1)  Today I started the profile class, which turned out to be very easy because the saving and loading is handled with Java's serializing.  I then moved on to fix the menu bug, which I did after a while of playing around with layouts and NetBeans swing editor.  It allows me to rapidly prototype and drag and drop elements.  It took a while, because the default free form layout doesn't scale with the windows, which is something I want with this game.  I ended up using a combination of Border and Grid layouts to get my desired look.  After that, I started to work on the profile gamestate, getting the profiles loaded and into the JList element.

2)  Next week I want to finish the profile gamestate completely and make all the drawn graphics scalable.  If I have time, I'll start on the options gamestate.

3) Today I learned that although Java Swing layouts are cumbersome with code, they are a lot easier to work with using a visible GUI.  I also learned that even through freeform seems to be the most flexible, it has numerous problems when working with a scalable window.  It took a lot of trial and error but I'm proud to say that using a combination of the two I have a really rapid system of menu development.  I anticipate that this will be extremely useful when doing the options, pause, and credits screen. 

Wednesday, October 12, 2011

Wednesday Post 3

1)  What I did today was to create a sound engine for my game.  I started using the AudioClip class which is used primarily for Applets, but found that it was too slow when running large audio files as well as two files at once.

Working from an example from http://www.oracle.com/technetwork/java/index-139508.html, I implemented the Java.sound api which works very well.  From there, I had to implement such functions as start, stop, pause, resume, pan, gain, and isPlaying.  After running some test cases, I've concluded that it is pretty complete for now.

I also started on the main menu for the primary purpose to see how using the java.swing objects would interact with the changing of gamestates.  That took about an hour to get that solved, and there's still a little bug where one in about every three runs the menu is all messed up in the GridLayout.  This has fairly low priority and my hunch is that I'm not initializing the size correctly or something minor like that.

2) Looking at the scrum board for next week, I want to make the profile system.  This is primarily file manipulation and a basic class, so it shouldn't take the entire class period.  If I get time, I want to implement some system in my View class that will scale my sprites with the window.. which is just essentially passing a ratio of the window size down along the render chain.

3)  Today was a successful day and I feel very relieved to have the trusty Java docs at my disposal.  The sound engine was a big part of it that I didn't have any idea what was going on going into it.  So here's some code:

This is the code for the SoundManager.  Its a singleton and basically has all the functions of the MySound class, and maps a bunch of MySounds to strings for easy retrieval.  It can be accessed from any part of the program to alter sounds wherever.

package seniorproj;



import java.util.HashMap;

public class SoundManager {

    private static HashMap sound_list;
    private static SoundManager instance=null;

    private SoundManager(){
        sound_list=new HashMap();
    }
    public static SoundManager get(){
        if (instance==null){
            instance=new SoundManager();
        }
        return instance;
    }
    public static void addSound(String name,String fname){
        sound_list.put(name,new MySound(fname));
    }
    public static int playSound(String name){
        MySound tmp=sound_list.get(name);
        if(tmp!=null){
            tmp.playSound();
            return 0;
        }
        else{
            return 1;
        }
    }
    public static int pauseSound(String name){
        MySound tmp=sound_list.get(name);
        if(tmp!=null){
            tmp.pauseSound();
            return 0;
        }
        else{
            return 1;
        }
    }
    public static int stopSound(String name){
        MySound tmp=sound_list.get(name);
        if(tmp!=null){
            tmp.stopSound();
            return 0;
        }
        else{
            return 1;
        }
    }
    public static int setLooping(String name,boolean b){
        MySound tmp=sound_list.get(name);
        if(tmp!=null){
            tmp.setLooping(b);
            return 0;
        }
        else{
            return 1;
        }
    }

    public static int setVolume(String name,float percent){
        MySound tmp=sound_list.get(name);
        if(tmp!=null){
            tmp.setVolume(percent);
            return 0;
        }
        else{
            return 1;
        }
    }
    public static int setPan(String name,float percent){
        MySound tmp=sound_list.get(name);
        if(tmp!=null){
            tmp.setPan(percent);
            return 0;
        }
        else{
            return 1;
        }
    }
    public static boolean isPlaying(String name){
        MySound tmp=sound_list.get(name);
        if(tmp!=null){
            return tmp.isPlaying();
        }
        return false;
    }

}


Next up is the MySound class, which loads the sound using Java.sound.  I was working off that example posted above.  After sifting through the code I've gotten a pretty good grasp of what is actually going on.  As you'll see, it has most of the same functions as the SoundManager.

/*
 * Based on http://www.oracle.com/technetwork/java/index-139508.html
 */

package seniorproj;

import javax.swing.*;
import javax.sound.sampled.*;
import java.io.File;


public class MySound extends JApplet {
    
    Object currentSound;
    String name;
    private boolean loop=true;

    public MySound(String fname){
        name=fname;
        loadSound(fname);
  
    }

    public boolean loadSound(String fname){
            File filein = new File(fname);

            try {
                currentSound = AudioSystem.getAudioInputStream(filein);
            }
            catch(Exception e1) {
                System.out.println("Could not getAudioInputStream");
                return false;
            }


           try {
                AudioInputStream stream = (AudioInputStream) currentSound;
                AudioFormat format = stream.getFormat();
                /**
                 * we can't yet open the device for ALAW/ULAW playback,
                 * convert ALAW/ULAW to PCM
                 */
                if ((format.getEncoding() == AudioFormat.Encoding.ULAW) ||
                    (format.getEncoding() == AudioFormat.Encoding.ALAW))
                {
                    AudioFormat tmp = new AudioFormat(
                                              AudioFormat.Encoding.PCM_SIGNED,
                                              format.getSampleRate(),
                                              format.getSampleSizeInBits() * 2,
                                              format.getChannels(),
                                              format.getFrameSize() * 2,
                                              format.getFrameRate(),
                                              true);
                    stream = AudioSystem.getAudioInputStream(tmp, stream);
                    format = tmp;
                }
                DataLine.Info info = new DataLine.Info(
                                          Clip.class,
                                          stream.getFormat(),
                                          ((int) stream.getFrameLength() *
                                              format.getFrameSize()));

                Clip clip = (Clip) AudioSystem.getLine(info);
                clip.open(stream);
                currentSound = clip;
            }
            catch (Exception ex) {
                ex.printStackTrace();
                currentSound = null;
                return false;
            }

        return true;

    }
    
    public void playSound(){
        if (currentSound!=null){
            Clip clip = (Clip) currentSound;
            if(loop==false)
                clip.start();
            else
                clip.loop(clip.LOOP_CONTINUOUSLY);
        }
        else{
            loadSound(name);
            Clip clip = (Clip) currentSound;
            clip.start();
        }
    }

    public void stopSound(){
        if (currentSound!=null){
            Clip clip = (Clip) currentSound;
            clip.stop();
            currentSound=null;
        }
    }

    public void pauseSound(){
        if (currentSound!=null){
            Clip clip = (Clip) currentSound;
            clip.stop();
        }
    }

    public void setVolume(float percent){
        if (currentSound!=null){
            if(percent<0)percent=0;
            if(percent>100)percent=100;
            percent/=100;
            try {
                Clip clip = (Clip) currentSound;
                FloatControl gainControl =
                  (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
                float dB = (float)
                  (Math.log(percent==0.0?0.0001:percent)/Math.log(10.0)*20.0);
                gainControl.setValue(dB);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    public void setPan(float percent){
        if (currentSound!=null){
            if(percent<-100)percent=-100;
            if(percent>100)percent=100;
            try {
                Clip clip = (Clip) currentSound;
                FloatControl panControl =
                    (FloatControl) clip.getControl(FloatControl.Type.PAN);
                panControl.setValue(percent/100);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
    public void setLooping(boolean b){
        loop=b;
    }

    public boolean isPlaying(){
        if(currentSound!=null){
            Clip clip = (Clip) currentSound;
            return clip.isRunning();
        }
        else
            return false;
    }
}

Wednesday, October 5, 2011

Wednesday Post 2

1) What I did today

Today I switched engines yet again.  JMonkey proved to be too young, and problems with documentation conflicts and buggy sound code forced me to try something else.  I will be trying a 2d solution with Java2D, a built in lib.

While this was rather frustrating, there are a few good things.  First, the UI is basically done because I can use Java.Swing.  The cursor is also done, because I can use MouseListeners with the default mouse.  I unintentionally got everything I wanted to accomplish today done, except for the DFA, which I'll probably end up putting off for winter break.

A couple of considerations with the new engine are the sound, which Java has built it (yet I have no experience with it and don't know its capabilities) and input.  For Joystick input, I'll probably have to use an external library like JxInput.

2)  What I will do next week

-Get the sound files playing on the play gamestate
-Create a MainMenu playstate

3) Etc.

Nothing to post.