Wednesday, December 7, 2011

Wednesday Post 9

1) Today I got the high score functionality in the game, including profile integration and the end of level screen. I also did a title screen. The High scores are flexible so that users can add their own songs if they like; it will automatically include them in the system.

2) Next week is the last of the semester, and there really isn't too much left as far as the skeleton of the game goes. The flow of gamestates is in place and everything SEEMS to be functioning properly. The one tail end from a hard days work today is that I need to calculate the average score and accuracy for the profiles. This should take maybe a half an hour. Next week I may work on my formal DFA for the game.

3) It seems that I made it on schedule, and although the game is basic, all the functionality I wanted in my design document is there. There is a lot of room for features, primarily in stat keeping and profile comparison, but I believe the design of the program is flexible enough to allow such additions if I choose to. Although they are not priorities, I may add them if I get all the graphics and sound implemented, toward the end of next semester.

The only other thing I want to add is possibly a custom GUI and get rid of swing; this would certainly make it prettier and theres a possibility that I could reuse a lot of the listeners/ActionPerformed methods I already have.

Wednesday, November 30, 2011

Wednesday Post 8

1) Lets look at the list I made for last week and see what I got done:

Scoring system
I implemented the scoring system, as described in the design document, but have not been able to test it yet. Next time I will test it with the game pad, which is why it resides in the "verify" column of the scrum board.

Investigation of skinnable swing elements
Custom LAF (look and feels) are surprisingly easy to integrate; just adding them to the classpath and a single call from the UIManager. However, for some reason the custom fonts are not working, so I have to investigate that further, which is now a task on the board.

High Scores/Profile integration
This part I started, but realized that I have no architecture for high scores besides the personal bests saved in the profile; these bests don't make sense either because they do not differentiate between difficulty levels. What I need to do is develop a completely new class that interfaces with the profile to not only record personal bests (on both difficulties) but allow comparison between other profiles and other bests. This will be the focus for next time.

Options Gamestate
I could not think of a single option that is absolutely necessary to the game, so I'm just skipping this for now.

Select level gamestate
I got this part all done except for displaying the personal bests, which is part of the problem from above. That's an easy fix though. Also, I can now select the difficulty levels.

2) Next week, I need to develop a new structure for high scores that make them easy to retrieve, sort, and compare. It will need to integrate with the profile. Along with this will be the end of song gamestate, which basically accumulates game data, calculates score, and reports it to the user and to the high score class.

If I have time, I need to write a python script to assist me in creating the song data files. The overall goal is to have a working example song by the end of the semester, with working profiles and high scores.


3) Nothing today.

Wednesday, November 16, 2011

Wednesday Post 7

1) Today I worked on getting gamepad input to work, which was a lot easier than I thought it would be. I'm using a library called JXInput, which sadly is not cross platform. I went ahead and set up some dummy "slide positions" for my normal gamepad so I could detect successful notes. What I thought would be super difficult really wasn't, and now its just a matter of optimizing the code so that the input is as accurate as possible.

2) As the semester wanes, the goal is to get a lot of the functional elements of the game done, and next semester will be primarily graphics and sound. The main things I need to do are:

Scoring system
Investigation of skinnable swing elements
High Scores/Profile integration
Options Gamestate
Select level gamestate


Over Holiday break I plan to finish up on the controller and get that fully integrated. I believe I can finish up what I have here in the next 4 weeks.

3) At the beginning, when I was switching around with engines, I thought it was a giant waste of time. One good thing that came from it though was I learned how to integrate jar libraries into my classpath and netbeans project, something I had no idea how to do before the engine shuffle. Today, I think this (and a little bit of luck with the documentation) is what I credit the success of JXInput.

Wednesday, November 9, 2011

Wednesday Post 6

1)  Today I made the progress bar, which proved to have its problems with the scaling. I also created a bitmap font class to create and display scalable bitmap fonts.

2)  Next week I'm going to finish up the HUD, then I'll go on to getting joystick input.

3)  Here is the bitmap font code :

package seniorproj;

import java.util.HashMap;
import java.awt.image.*;
import java.awt.*;

public class BitmapFont {

    private HashMap img_list;
    private int cell_size;

    public BitmapFont(int size, Color c){
        img_list=new HashMap();
        cell_size=size;
        //numbers
        for(int xx=48;xx<=57;xx++){
            BufferedImage b = new BufferedImage(size,size*2,BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2 = b.createGraphics();
            g2.setFont(new Font("Arial",0,size));
            g2.setPaint(c);
            g2.drawString(Character.toString((char)xx),size/2,size);
            img_list.put(Character.toString((char)xx),b);
        }
        //uppercase
        for(int xx=65;xx<=90;xx++){
            BufferedImage b = new BufferedImage(size,size*2,BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2 = b.createGraphics();
            g2.setFont(new Font("Arial",0,size));
            g2.setPaint(c);
            g2.drawString(Character.toString((char)xx),size/2,size);
            img_list.put(Character.toString((char)xx),b);
        }
        //lowercase
        for(int xx=97;xx<=122;xx++){
            BufferedImage b = new BufferedImage(size,size*2,BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2 = b.createGraphics();
            g2.setFont(new Font("Arial",0,size));
            g2.setPaint(c);
            g2.drawString(Character.toString((char)xx),size/2,size);
            img_list.put(Character.toString((char)xx),b);
        }


    }

    public void render_string(Graphics2D g2,int x, int y, String str, float rw, float rh){
        for(int xx=0;xx

Wednesday, November 2, 2011

Wednesday Post 5

1)  Today was a productive day, as I got the entire profile gamestate completed (add, remove, select), made the graphics scalable, and began working on the HUD.  I also made a credits notification box, which took a single line of code.

2)  Next week will be a 100% focus on the Play gamestate.  I want to focus on designing the layout and basic look of the play field without getting hung up on graphics too much.  The goals for the end of next week will be to have blobs moving, a basic backgroudn designed with the game in mind, and a hud containing score, multiplier, and a progress bar.

3)  Came across my first bug today that I'm leaving in for now.  It seems that when I clear the text area and then add text directly afterward, the window freezes.  For now it just appends the text area with the profile information, which is good enough for now.  I'm glad I let it go after working on it, so I could move on to more important things. 

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.

Wednesday, September 28, 2011

Wednesday Post 1

Wednesday posts will have a new format:  1) What I did today 2) What the goals are for next week with time frames 3)  Reflection/Misc/Interesting Code

1) What I did today

Today I continued to nail down the skeleton of how the game's main classes work together.  One of the tasks I undertook was to flesh out the data file loading of the levels and songs.  The SelectLevel game state looks into a directory and loads all the level files it finds, then those levels load the song data, now complete with the sound files.  Now that I had two game states, I added a static function in the main that changes the game state.  Because the main's update function simply calls the current game state's update, all it does is switch the cur_gamestate variable to a newly created gamestate.

One problem I encountered was playing audio.  It seems to be loaded in correctly, and all the correct properties are set, but there is a NullPointerException within the actual engine code.  I signed up for the forum so I can ask some experts.

2)  Next week's goals are as follows:

Disabling the default keymappings and adding my own:
  Disabling all except for escape key:  .5 Hours
  Creating a class for a 2d cursor, mapping input:  2 Hours
  Simple GUI Button:  2.5 Hours
  Official DFA for gamestates:  1 Hour

I anticipate quite a bit of time for the button because it will require a textured quad billboard, rendered text, and ray casting/picking.  The DFA was suggested by Andrew as being a good showcase piece for future employers/celebration of scholarship.

3) Reflection/Misc/Interesting Code

Today I coded straight from 8:00 till 5:00.  To me this felt like a marathon but in retrospect this is just a typical day in the workplace.  My brain feels fried; hopefully I adjust to this sort of thing. 
 

Wednesday, September 21, 2011

jMonkey

I decided to go with jMonkey, an engine built on lwjgl because it has a lot of things done that I would need, like fonts, textures, physics, scenegraphs, etc.  So far its been working pretty well.

I've been working on get the basic skeleton of my game layed out.  I have a gamestate, level, song, and numerous blobs working.  It recognizes the difference between special blobs and normal blobs, and draws them going across the screen at the right time.

I keep doing stupid stuff like initializing code in the wrong order or deleting materials and wondering where they went, and its frustrating because I'm shooting myself in the foot by wasting time with stupid mistakes.  Next week I'm going to work on the menu style gamestates, like the main menu, credit screen, and others.

Here's a picture: