Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (483)
Games in Android Showcase (110)
games submitted by our members
Games in WIP (550)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Sounds On Keypress  (Read 4854 times)
0 Members and 1 Guest are viewing this topic.
Offline vection

Senior Newbie





« Posted 2010-06-01 22:13:26 »

Hey everyone,
I'm new to this website and also kinda new to Java but am using BlueJ to code a game as a side project. I am making a 2d Fighting Game. I don't know how to make it so when it punches it makes the sound, so like A and D to walk left and right across the screen and E for punch and R to kick, I'm trying to make it so when you press the corresponding buttons the sounds will play for either punching or kicking. Can anyone help me with this? Thanks In Advance  Smiley
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #1 - Posted 2010-06-02 14:25:17 »

Well this is really a question of two things:

a) How do I respond to key presses
and
b) How do I play sounds

If you know both you should be able to do what you want.

If you're using Swing, key presses are pretty easy
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
public class MyWindow extends JFrame implements KeyListener
{
    // a bunch of your class's stuff

    public void keyPressed(KeyEvent e)
    {
        int i = e.getKeyChar();
        if (i == KeyEvent.VK_UP)
        {
            // Move up!
       }
        //etc.
   }

    public void keyReleased(KeyEvent e)
    {
        int i = e.getKeyChar();
        if (i == KeyEvent.VK_A)
        {
            System.out.println("Punch!");
        }
        else if (i == KeyEvent.VK_B)
        {
            System.out.println("Kick!");
        }
    }

    public void keyTyped(KeyEvent e) {//do nothing}
}
[code]

As for sounds, this is a much more complicated beast. Have a look around the forums and you should find many, many, different ways of implementing it.
[/code]

See my work:
OTC Software
Offline paulscode

Senior Member


Medals: 12


Staff Sergeant


« Reply #2 - Posted 2010-06-02 19:44:36 »

Sound doesn't have to be complicated, either.  The easiest option is probably my SoundSystem Library (perhaps overkill for your project, but very easy to use).  You would need the SoundSystem core, LibraryJavaSound plug-in, and a codec plug-in (CodecWav, for example).  Assuming you have sound files named "punch.wav" and "kick.wav", you would compile them into your JAR in a package/directory named "Sounds".   Here is Demonpants' example with sound effects added in:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
// Add these imports at top of the program:
import paulscode.sound.SoundSystem;
import paulscode.sound.SoundSystemConfig;
import paulscode.sound.SoundSystemException;
import paulscode.sound.libraries.LibraryJavaSound;
import paulscode.sound.codecs.CodecWav;
//...etc

// And you'll need a SoundSystem handle:
SoundSystem mySoundSystem;

public class MyWindow extends JFrame implements KeyListener
{
    // Call initSound() from the constructor or from an initialization method:
   public void initSound()
    {
        try
        {
            SoundSystemConfig.addLibrary( LibraryJavaSound.class );
            SoundSystemConfig.setCodec( "wav", CodecWav.class );
            mySoundSystem = new SoundSystem();
        }
        catch( SoundSystemException sse )
        {
            sse.printStackTrace();
        }
    }

    // A method for quickly playing a sound file:
   public void quickPlay( String filename )
    {
        mySoundSystem.quickPlay( false, filename, false,
            0, 0, 0,
            SoundSystemConfig.ATTENUATION_ROLLOFF,
            SoundSystemConfig.getDefaultRolloff() );
    }
 
    public void keyPressed(KeyEvent e)
    {
        int i = e.getKeyChar();
        if (i == KeyEvent.VK_UP)
        {
            // Move up!
       }
        //etc.
   }

    public void keyReleased(KeyEvent e)
    {
        int i = e.getKeyChar();
        if (i == KeyEvent.VK_A)
        {
            System.out.println("Punch!");
            quickPlay( "punch.wav" );
        }
        else if (i == KeyEvent.VK_B)
        {
            System.out.println("Kick!");
            quickPlay( "kick.wav" );
        }
    }

    public void keyTyped(KeyEvent e) {//do nothing}
}

We love death.  The US loves life.  That is the difference between us.  -Osama bin Laden, mass murderer
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline vection

Senior Newbie





« Reply #3 - Posted 2010-06-02 22:45:28 »

I appreciate the help you guys, I found something that seems to be working for it so far, but is this okay or do I need to do something more complicated?
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
import java.awt.*;
import java.applet.*;

public class Project30 extends Applet
{
   Image Buffer;
   Graphics gBuffer;
   boolean pressedLeft, pressedRight, pressedUp, pressedDown;
   AudioClip mySound1;
   AudioClip mySound2;
   AudioClip mySound3;
   AudioClip mySound4;
   AudioClip mySound5;


   public void init()
   {
      Buffer=createImage(size().width,size().height);
      gBuffer=Buffer.getGraphics();

      try
      {
           mySound1=getAudioClip(getCodeBase(),"punch.wav");
           mySound2=getAudioClip(getCodeBase(),"kick.wav");
           mySound3=getAudioClip(getCodeBase(),"punch2.wav");
           mySound4=getAudioClip(getCodeBase(),"punch3.wav");
           mySound5=getAudioClip(getCodeBase(),"sword.wav");
      }

      catch (Exception e){}
   }

   public boolean keyDown(Event e, int key)
   {
      if(key==Event.LEFT)
      pressedLeft=true;

      if(key==Event.RIGHT)
      pressedRight=true;

      if(key==Event.UP)
      pressedUp=true;
      if(key==Event.DOWN)
      pressedDown=true;

      if(key=='s'||key=='S')
           mySound1.play();

      if(key=='e'||key=='E')
           mySound2.play();      
           
      if(key=='r'||key=='R')
           mySound3.play();
           
      if(key=='q'||key=='Q')
           mySound4.play();
 
      if(key=='d'||key=='D')
           mySound5.play();
           
      if(key=='9'||key=='9')
           mySound5.play();
           
      repaint();

      return true;
   }
Offline vection

Senior Newbie





« Reply #4 - Posted 2010-06-02 23:19:38 »

Also I would like a song playing in the background as all this is going on, how would I go about that?
Offline paulscode

Senior Member


Medals: 12


Staff Sergeant


« Reply #5 - Posted 2010-06-03 02:49:47 »

That should work fine for playing short clips.  Background music depends on the length of the song and the format.

There is a maximum size that an audio clip can be (generally around 5 seconds or so, depending on the quality).  If your song is longer than that, you will need to "stream" it.  That's where you feed the data to a line in chunks over time (as one chunk finishes, you feed in another).  Most developers will run that process on a separate Thread.

If your song is a MIDI file, you don't stream it.  MIDI is a complicated format, not like other audio formats.  In that case, you would read the data from the MIDI file (called the Sequence), pass that information to an available Sequencer, and link that to an available Synthesizer which outputs the music.

If you need to do either of these two options (i.e. if your music is too long or if it is MIDI), then I recommend using the SoundSystem library I mentioned earlier, because it makes both of these processes much easier (1 line of code vs. 30 lines).
After initializing the SoundSystem as mentioned in my earlier post, you can simply use the backgroundMusic method (works for both MIDI and for long audio files):
1  
mySoundSystem.backgroundMusic( "Background Music", "beethoven.mid", true );

We love death.  The US loves life.  That is the difference between us.  -Osama bin Laden, mass murderer
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #6 - Posted 2010-06-03 02:58:50 »

If you want to use AudioClip to play music (AudioClip, in my opinion, is the easiest way to get sound to work at a very minimal level), you can just link a sounds like you did otherwise except call mySound.loop() instead of mySound.play(). The big problem with this, aside from AudioClip sucking many ways in general, is that you can't use compressed audio in any fashion whatsoever. So your game will be 99% sounds (in terms of disk space) if you don't use compressed audio.

paulscode's library is great, but it might be too difficult for you at this point to use external libraries - if you're not worried about file size and potential issues just stick with AudioClip.

See my work:
OTC Software
Offline paulscode

Senior Member


Medals: 12


Staff Sergeant


« Reply #7 - Posted 2010-06-03 11:06:56 »

I just noticed you were using java.applet.AudioClip (for some reason I interpreted this as javax.sound.sampled.clip).  Disregard my comment about the length limitation.  AudioClip can play longer files I believe, and it supports the wav, .au, and .aif formats.  The limitation with this method is that it only provides play(), loop(), and stop() functions, and the supported file formats can get rather large in size as Demonpants pointed out (especially if you are considering music).  Otherwise, it is a simple solution.

We love death.  The US loves life.  That is the difference between us.  -Osama bin Laden, mass murderer
Offline vection

Senior Newbie





« Reply #8 - Posted 2010-06-03 22:02:48 »

So to use AudioClip I need to add a new thread? is that what you were saying?
Offline vection

Senior Newbie





« Reply #9 - Posted 2010-06-03 22:12:51 »

Also if I wanted a sound to play right at the beginning to say like Fight! or something like that how would I just add that to play once at the very beginning and then not play anymore till the next time it is played, or make it so at the end of the game it says You Win! Thanks for all the help
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline vection

Senior Newbie





« Reply #10 - Posted 2010-06-03 22:37:02 »

Lol wow I feel stupid lol. Sorry I was not paying attention to what I was saying, I already have the audioclip but how do I make background music into it?
Offline paulscode

Senior Member


Medals: 12


Staff Sergeant


« Reply #11 - Posted 2010-06-04 11:03:30 »

I've never used AudioClip myself, to be honest.  Is there a limitation with this class preventing you from creating and playing a couple of AudioClip's for your "Fight!" sound and the background music, somewhere at the beginning of your program (say in the init() method)?

1  
2  
3  
4  
5  
6  
try
{
    getAudioClip( getCodeBase(), "FIGHT!!!.wav" ).play();
    getAudioClip( getCodeBase(), "myCoolMusic.wav" ).play();
}
catch( Exception e ){}


I'm assuming AudioClip's play in the background (according to JavaDoc they play on their own thread).  Is that not the case, or are you only able to play one at a time or something?

We love death.  The US loves life.  That is the difference between us.  -Osama bin Laden, mass murderer
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #12 - Posted 2010-06-04 17:46:34 »

vection, you should probably study up a bit more on Java in general if you can. Your questions are not really sound related. Here is a simple pseudo code game that has background music and plays sounds when you press buttons.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
public class SimpleGame
{
    AudioClip music;
    AudioClip punchSound;
    AudioClip fightSound;

    public void preloadGame()
    {
        try
        {
            music = getAudioClip( getCodeBase(), "music.aif");
            punchSound = getAudioClip( getCodeBase(), "punch.aif");
            fightSound = getAudioClip( getCodeBase(), "fight.aif");

            player.initializePlayer();
            world.preloadWorld();
            //etc.
       }
        catch (Exception e)
        {
            e.printStackTrace();
            System.exit(1);
        }
    }

    public void startGame()
    {
        music.loop();
        fightSound.play();

        while (inGameLoop)
        {
            player.update();
            world.update();
            //etc.
       }
    }

    public void keyPressed(KeyEvent e)
    {
        if (e.getKeyCode() == KeyEvent.VK_A)
        {
            player.punch();
            punchSound.play();
        }
    }
}


That should hopefully illuminate things for you, even though the code's design is totally retarded (for example, you wouldn't play sounds from the main class, you would have player.punch() play the punch sound, and world.startGame() play the fight sound and the music) and the game loop is totally BS.

See my work:
OTC Software
Offline vection

Senior Newbie





« Reply #13 - Posted 2010-06-07 22:34:04 »

I've never used AudioClip myself, to be honest.  Is there a limitation with this class preventing you from creating and playing a couple of AudioClip's for your "Fight!" sound and the background music, somewhere at the beginning of your program (say in the init() method)?

1  
2  
3  
4  
5  
6  
try
{
    getAudioClip( getCodeBase(), "FIGHT!!!.wav" ).play();
    getAudioClip( getCodeBase(), "myCoolMusic.wav" ).play();
}
catch( Exception e ){}


I'm assuming AudioClip's play in the background (according to JavaDoc they play on their own thread).  Is that not the case, or are you only able to play one at a time or something?

This actually worked perfectly for me, I just need to find out how to loop the song after the song ends. Smiley
Offline vection

Senior Newbie





« Reply #14 - Posted 2010-06-07 23:48:22 »

Ok so now how would I make it so the ouch sound would play when the characters get hit by a punch or kick?
Offline paulscode

Senior Member


Medals: 12


Staff Sergeant


« Reply #15 - Posted 2010-06-08 01:14:29 »

This actually worked perfectly for me, I just need to find out how to loop the song after the song ends. Smiley
As Demonpants suggested, why not just use loop() instead of play()?

Ok so now how would I make it so the ouch sound would play when the characters get hit by a punch or kick?
The same way you are playing a sound when a key is pressed, you would simply create your AudioClip instance at the beginning of your program, and then call play() on it when an impact occurred.

We love death.  The US loves life.  That is the difference between us.  -Osama bin Laden, mass murderer
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #16 - Posted 2010-06-08 15:22:35 »

I wouldn't recommend doing it exactly as paulscode suggested, as you're instantiating a new sound every single time you play it, which is crazy wasteful and really really slow. I think he put that example there just to give you a clearer idea of what's going on. Instead, do as I suggested, and store the sound somewhere, only to play it later.

And honestly I'm sort of frustrated with you at this point as you don't seem to be actually reading what we're saying to you. You have now been told three times how to loop a sound.

Quote
If you want to use AudioClip to play music (AudioClip, in my opinion, is the easiest way to get sound to work at a very minimal level), you can just link a sounds like you did otherwise except call mySound.loop() instead of mySound.play().

Quote
music.loop();
fightSound.play();

Quote
As Demonpants suggested, why not just use loop() instead of play()?

Similarly, you asking now how to make an ouch sound shows that in general you just don't understand what you're doing yet. Go back to basics and learn how code / Java work, because your comprehension right now is severely limited. To play a sound, anywhere, at any time, you use sound.play() at the bit of code where you would want the sound to play. It's the same concept. Exactly the same.

See my work:
OTC Software
Offline paulscode

Senior Member


Medals: 12


Staff Sergeant


« Reply #17 - Posted 2010-06-08 15:57:58 »

I wouldn't recommend doing it exactly as paulscode suggested, as you're instantiating a new sound every single time you play it, which is crazy wasteful and really really slow.
Just to clarify, my suggestion was for the two sounds that are played only once, in which case you would not be instantiating a new sound every single time you play it, because you are only playing it once.

We love death.  The US loves life.  That is the difference between us.  -Osama bin Laden, mass murderer
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #18 - Posted 2010-06-08 16:44:00 »

Just to clarify, my suggestion was for the two sounds that are played only once, in which case you would not be instantiating a new sound every single time you play it, because you are only playing it once.
Ah, that makes more sense, then. I didn't realize that. Smiley

See my work:
OTC Software
Offline vection

Senior Newbie





« Reply #19 - Posted 2010-06-10 23:51:33 »

Sound doesn't have to be complicated, either.  The easiest option is probably my SoundSystem Library (perhaps overkill for your project, but very easy to use).  You would need the SoundSystem core, LibraryJavaSound plug-in, and a codec plug-in (CodecWav, for example).  Assuming you have sound files named "punch.wav" and "kick.wav", you would compile them into your JAR in a package/directory named "Sounds".   Here is Demonpants' example with sound effects added in:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
// Add these imports at top of the program:
import paulscode.sound.SoundSystem;
import paulscode.sound.SoundSystemConfig;
import paulscode.sound.SoundSystemException;
import paulscode.sound.libraries.LibraryJavaSound;
import paulscode.sound.codecs.CodecWav;
//...etc

// And you'll need a SoundSystem handle:
SoundSystem mySoundSystem;

public class MyWindow extends JFrame implements KeyListener
{
    // Call initSound() from the constructor or from an initialization method:
   public void initSound()
    {
        try
        {
            SoundSystemConfig.addLibrary( LibraryJavaSound.class );
            SoundSystemConfig.setCodec( "wav", CodecWav.class );
            mySoundSystem = new SoundSystem();
        }
        catch( SoundSystemException sse )
        {
            sse.printStackTrace();
        }
    }

    // A method for quickly playing a sound file:
   public void quickPlay( String filename )
    {
        mySoundSystem.quickPlay( false, filename, false,
            0, 0, 0,
            SoundSystemConfig.ATTENUATION_ROLLOFF,
            SoundSystemConfig.getDefaultRolloff() );
    }
 
    public void keyPressed(KeyEvent e)
    {
        int i = e.getKeyChar();
        if (i == KeyEvent.VK_UP)
        {
            // Move up!
       }
        //etc.
   }

    public void keyReleased(KeyEvent e)
    {
        int i = e.getKeyChar();
        if (i == KeyEvent.VK_A)
        {
            System.out.println("Punch!");
            quickPlay( "punch.wav" );
        }
        else if (i == KeyEvent.VK_B)
        {
            System.out.println("Kick!");
            quickPlay( "kick.wav" );
        }
    }

    public void keyTyped(KeyEvent e) {//do nothing}
}

Sorry, is it possible to explain this with more depth? The other way didn't end up working in the end Sad
Thanks.
Offline paulscode

Senior Member


Medals: 12


Staff Sergeant


« Reply #20 - Posted 2010-06-11 15:51:02 »

is it possible to explain this with more depth?
Sure.

Step #1 Download the .zip files you want to use.  For example:

1) The core SoundSystem library
2) Library JavaSound plug-in
3) CodecWav (you need a codec for each format your sounds are saved in)

Step #2 Unzip them, and pull out the .jar files:

SoundSystem.jar
LibraryJavaSound.jar
CodecWav.jar (or any other codecs that you will be using)

Step #3 Tell the Java compiler about the .jar files from step 2.  How to do this step depends entirely on which GUI you are using to develop your project (if you are using one), so I can't explain that here (google is your friend).  I personally use NetBeans, so if that is what you are using, I can explain how to do this in more detail.

Step #4 Place all the audio files you will be using into a package named "Sounds/".  Again, this depends on your GUI.

Step #5 Include the necessary imports at the top of your program.  For example:
1  
2  
3  
4  
5  
import paulscode.sound.SoundSystem;
import paulscode.sound.SoundSystemConfig;
import paulscode.sound.SoundSystemException;
import paulscode.sound.libraries.LibraryJavaSound;
import paulscode.sound.codecs.CodecWav;


Step #6 Tell the SoundSystem which plug-ins you plan to use.  For example:
1  
2  
3  
4  
5  
6  
7  
8  
9  
        try
        {
            SoundSystemConfig.addLibrary( LibraryJavaSound.class );
            SoundSystemConfig.setCodec( "wav", CodecWav.class );
        }
        catch( SoundSystemException sse )
        {
            sse.printStackTrace();
        }


Step #7 Instantiate the SoundSystem.  For example:
1  
        mySoundSystem = new SoundSystem();


Step #8 (optional) Pre-load all short sound files.  For example:
1  
2  
3  
4  
        mySoundSystem.loadSound( "fight.wav" );
        mySoundSystem.loadSound( "punch.wav" );
        mySoundSystem.loadSound( "kick.wav" );
        mySoundSystem.loadSound( "ouch.wav" );

Note: I did not pre-load the music, because that will be streamed directly instead, in order to save memory which is rather limited in applets.

Step #9 (optional) Create a method to simplify quick-playing the sound effects:
1  
2  
3  
4  
5  
6  
7  
    public void quickPlay( String filename )
    {
        mySoundSystem.quickPlay( false, filename, false,
            0, 0, 0,
            SoundSystemConfig.ATTENUATION_ROLLOFF,
            SoundSystemConfig.getDefaultRolloff() );
    }


Step #10 Stream the music when it is time to play it:
1  
        mySoundSystem.backgroundMusic( "Some cool music!", "song.wav", true );


Step #11 Play the sound effects when it is time to play them.  For example:
1  
        quickPlay( "fight.wav" );


Thats about it.  The SoundSystem library is quite simple as audio libraries go, so you shouldn't have too much trouble using it once you are comfortable programming in Java.

I recommend reading the tutorial I wrote 3D Sound with SoundSystem if you are serious about using the library, as it will familiarize you with the termonology and walk you through several example programs.

We love death.  The US loves life.  That is the difference between us.  -Osama bin Laden, mass murderer
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CopyableCougar4 (15 views)
2014-08-22 19:31:30

atombrot (28 views)
2014-08-19 09:29:53

Tekkerue (25 views)
2014-08-16 06:45:27

Tekkerue (23 views)
2014-08-16 06:22:17

Tekkerue (15 views)
2014-08-16 06:20:21

Tekkerue (22 views)
2014-08-16 06:12:11

Rayexar (61 views)
2014-08-11 02:49:23

BurntPizza (39 views)
2014-08-09 21:09:32

BurntPizza (31 views)
2014-08-08 02:01:56

Norakomi (38 views)
2014-08-06 19:49:38
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!