Super Mario – Duckhunt Edition

Another friend gets married!

Time to foresee something special again. Previously, we have already made a Gorilla Piñata and a Wheel of Fortune. So we can’t do anything less this time!

Mario mario mario…

My friend David is quite the Mario fan: when he proposed to his girlfriend, he hid the ring in a coin block.

And for the bachelor party, he rode a go-kart dressed up as Mario.

This left us with no other choice than to foresee something in the Mario theme.

Duck Hunt

One night at the pub, we were discussing about the wedding. My friend Colin came up with the idea for a duckhunt game in Mario style. The goal of the game is to hit as many targets as possible. And of course,we need different levels and a high score.

I did the programming, and my friend Robin did all the graphical work.

Game features

  • Left click to shoot
  • Right click to reload
  • Multiple targets
  • 20 levels
  • Game speed increases across levels
  • Midi music
  • High score
  • And there’s even a Toasty! popup where you can see the makers

The wedding present

As mentioned before, we made this game as a wedding present. At the wedding party, David had to play the game.

But they could only get their present once they had beaten the high score of all their friends. We all played the game and posted our high scores online. The newlyweds had to play for hours until they could beat our high score and receive their gift!

Coding

The coding is written in Java, and – given the tight deadline – it’s not really my cleanest code. I started off from Ynori7’s code for a Duckhunt game.

/**
 * @(#)DuckHunt.java
 *
 * Duck_Hunt application
 *
 * @author 
 * @version 1.00 2014/5/6
 */
 

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.KeyEvent;
    import java.awt.geom.*;
    import java.awt.event.KeyListener;
    import java.awt.event.*;
    import java.awt.image.*;
    import java.io.*;
    import java.util.*;
    import java.text.DecimalFormat;
    import java.applet.*;
     
     
    /**
    * Most awesome game ever.
    * Known Flaws: Game speed is dependent on cpu speed.
    *
    * @author Ynori7 + Barre
    * @version June 2007 + May 2014
    */
    public class DuckHunt extends JPanel implements Runnable, ImageObserver, MouseMotionListener, MouseListener
    {
	    JFrame frame;
	    Thread thread;
	    int xRes = 1280;
	    int yRes = 960;
	    Image[] picture = new Image[2];
	    Image bg = Toolkit.getDefaultToolkit().getImage( "images/level1.png" );
	    Image crosshair = Toolkit.getDefaultToolkit().getImage( "images/crosshair.png" );
	    Image shotImg = Toolkit.getDefaultToolkit().getImage( "images/shot.png" );
	    Image bullet = Toolkit.getDefaultToolkit().getImage( "images/bullet.png" );
	    Image toastyImage1 = Toolkit.getDefaultToolkit().getImage( "images/toasty1.png" );
	    Image toastyImage2 = Toolkit.getDefaultToolkit().getImage( "images/toasty2.png" );
	    Image toastyImage3 = Toolkit.getDefaultToolkit().getImage( "images/toasty3.png" );
	    
	    /*Image duck1 = Toolkit.getDefaultToolkit().getImage( "duck1.png" );
	    Image duck2 = Toolkit.getDefaultToolkit().getImage( "duck2.png" );
	    Image duck3 = Toolkit.getDefaultToolkit().getImage( "duck3.png" );*/
	    Image splat = Toolkit.getDefaultToolkit().getImage( "images/splat.png" );
	    Image[] ducks = new Image[3];
	    AudioClip sound, sounda, soundb, soundc, toasty, music;
	    Rectangle duckLoc;
	    int duckx=10, ducky=10, xvel=2, yvel=2, dImg=0;
	    int x, y, killScore = 0, esc=0, hits=0, shots=0;
	    double acc=0;
	    int xpos, ypos, z, p=0;
	    int time, ammo=3, counter=0;
	    int direction = 0;
	    int dsizex=100, dsizey=100;
	    boolean shot = false, hit = false;
	    Random rand = new Random();
	    DecimalFormat df = new DecimalFormat("0.00");
	    int initialSpeed = 20;
	    int speed = initialSpeed;
	    int level = 1;
	    int increasePerKill = 10;
	    int score = 0;
	    String lastMessage = "";
	    int flewAwayFrameCounter = 0;
	    String[] imageList = {"duck","Mario","Peach","Samen","Peach2","Mario2","sterre ","Mario3"};
	    Font customFont = null;
	    int lastScore;
	    int toastyScore1 = 100000;
	    //int toastyScore1 = 2000;
	    boolean toastyPlay1 = false;
	    int toastyScore2 = 50000;
	    //int toastyScore2 = 4000;
	    boolean toastyPlay2 = false;
	    int toastyScore3 = 75000;
	    //int toastyScore3 = 6000;
	    boolean toastyPlay3 = false;
	    int toastyCounter = 0;
	    
	    
	    

	    
    
    public DuckHunt(final AudioClip sound1, final AudioClip sound2, final AudioClip sound3, final AudioClip sound4, final AudioClip toastySnd, final AudioClip music2)
    {
	    frame = new JFrame();
	    setBackground( Color.black );
	    // Set up the frame's graphics.
	    sound = sound1;
	    sounda = sound2;
	    soundb = sound3;
	    soundc = sound4;
	    toasty = toastySnd;
	    music = music2;
	    music.loop();
	    frame.add( this );
	    // Set up listeners.
	    addMouseMotionListener( this );
	    addMouseListener( this );
	    frame.setResizable( false );
	    
	    //determine screen size
	    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
	    System.out.println(screenSize.getWidth());
		xRes = (int) screenSize.getWidth();
		yRes = (int) screenSize.getHeight();
		//xRes = 1200;
		//yRes = 675;
		//System.out.println("x: "+xRes);
		//System.out.println("y: "+yRes);
		
		//calculate 4:3 aspect ratio
		int yResAR = xRes / 4 * 3;
		int xResAR = yRes / 3 * 4;
		
		//System.out.println("ARx: "+xResAR);
		//System.out.println("ARy: "+yResAR);
		
		if (yResAR > yRes){
			xRes = xResAR;
		}else{
			yRes = yResAR;
		}
		
		//System.out.println("res x: " +xRes);
		//System.out.println("res y: "+yRes);
		
	    
	    setPreferredSize( new Dimension( xRes, yRes ) );
	    //setPreferredSize( new Dimension( 850, 520 ) );
	    frame.pack();
	    frame.setVisible( true );
	    /*ducks[0]=duck1;
	    ducks[1]=duck2;
	    ducks[2]=duck3;*/
	    
	    //custom font
	    try {
	    	if(xRes >= 1200){
	    		customFont = Font.createFont(Font.TRUETYPE_FONT, new File("fonts/SuperMario256.ttf")).deriveFont(24f);
	    	}else if (xRes >= 1000){
	    		customFont = Font.createFont(Font.TRUETYPE_FONT, new File("fonts/SuperMario256.ttf")).deriveFont(20f);
	    	}else{
	    		customFont = Font.createFont(Font.TRUETYPE_FONT, new File("fonts/SuperMario256.ttf")).deriveFont(16f);
	    	}
	    	
	    } catch(Exception e) {
	    	System.out.println("font fout");
	    }
	    
	    
	    setRandomDuckImage();
	    thread = new Thread( this );
	    thread.start();
    }
     
    public void run()
    {
	    while( true )
	    {
		    // Code in here...
		    // Give some time to other stuff, if it needs it.
		    try {
		  		Thread.sleep(speed);
		    } catch( InterruptedException e ) { }
		     
		    // Force repaint.
		    repaint();
	    }
    }
    
    
    public void paintComponent( Graphics gc )
    {
	    // Clear the window.
	    super.paintComponent( gc );
	    //gc.drawImage(bg, 0, 0, 850, 520, null);
	    
	    gc.drawImage(bg, 0, 0, xRes, yRes, null);

	    
	    //transparant rectangle
        //gc.setColor(new Color(211,211,211,128));
        //gc.fillRect(2,2,400,100);
	    
	    if (xRes >= 1200){
	    
		    //text
		    gc.setColor(new Color(0xF5F5F5));
		    gc.setFont(customFont);
		    gc.drawString("Score: "+score+"", 20, 30);
		    gc.drawString("Kills: "+killScore+"", 20, 50);
		    gc.drawString("Level: "+level+"", 20, 70);
		    gc.drawString(lastMessage+"", 20, 90);
		    
		    //ammo
		    for(int q=0; q<ammo; q++)
		    {
		    	gc.drawImage(bullet, 10+(q*20), 85, 37, 81, null);
		    }
	    }else if (xRes >= 1000){
	    	//text
		    gc.setColor(new Color(0xF5F5F5));
		    gc.setFont(customFont);
		    gc.drawString("Score: "+score+"", 20, 22);
		    gc.drawString("Kills: "+killScore+"", 20, 42);
		    gc.drawString("Level: "+level+"", 20, 62);
		    gc.drawString(lastMessage+"", 20, 82);
		    
		    //ammo
		    for(int q=0; q<ammo; q++)
		    {
		    	gc.drawImage(bullet, 10+(q*15), 70, 30, 60, null);
		    }
	    }else{
	    	//text
		    gc.setColor(new Color(0xF5F5F5));
		    gc.setFont(customFont);
		    gc.drawString("Score: "+score+"", 20, 15);
		    gc.drawString("Kills: "+killScore+"", 20, 30);
		    gc.drawString("Level: "+level+"", 20, 45);
		    gc.drawString(lastMessage+"", 20, 60);
		    
		    //ammo
		    for(int q=0; q<ammo; q++)
		    {
		    	gc.drawImage(bullet, 10+(q*10), 55, 20, 40, null);
		    }
	    	
	    }
	    
	    
	    //play mk toasty sound when score reaches a certain level (especially for Colin)
	    if (lastScore < toastyScore1 && score >= toastyScore1){
	    	toasty.play();
	    	toastyPlay1 = true;
	    }
	    
	    //show toasy image for 50 frames
	    if (toastyPlay1 && toastyCounter < 50){
	    	gc.drawImage(toastyImage1,xRes-200,yRes-200,200,200,null);
	    	toastyCounter++;
	    	
	    	if(toastyCounter == 50){
	    		toastyCounter = 0;
	    		toastyPlay1 = false;
	    	}
	    }
	    
	    //play mk toasty sound when score reaches a certain level (especially for Colin)
	    if (lastScore < toastyScore2 && score >= toastyScore2){
	    	toasty.play();
	    	toastyPlay2 = true;
	    }
	    
	    //show toasy image for 50 frames
	    if (toastyPlay2 && toastyCounter < 50){
	    	gc.drawImage(toastyImage2,xRes-200,yRes-200,200,200,null);
	    	toastyCounter++;
	    	
	    	if(toastyCounter == 50){
	    		toastyCounter = 0;
	    		toastyPlay2 = false;
	    	}
	    }
	    
	    //play mk toasty sound when score reaches a certain level (especially for Colin)
	    if (lastScore < toastyScore3 && score >= toastyScore3){
	    	toasty.play();
	    	toastyPlay3 = true;
	    }
	    
	    //show toasy image for 50 frames
	    if (toastyPlay3 && toastyCounter < 50){
	    	gc.drawImage(toastyImage3,xRes-200,yRes-200,200,200,null);
	    	toastyCounter++;
	    	
	    	if(toastyCounter == 50){
	    		toastyCounter = 0;
	    		toastyPlay3 = false;
	    	}
	    }
	    
	    
	    
	    lastScore = score;
	    
	    
	    
    
	    /*if(shots>0)
	    {
		    acc= ((double)hits/(double)shots)*100;
		    gc.drawString("Accuracy: "+df.format(acc)+"%", 700, 515);
	    }*/
    
    	gc.drawImage(crosshair, x-27, y-27, 54, 54, null);
    
	    if(shot == true)
	    {
		    gc.drawImage(shotImg, xpos, ypos, 54, 54, null);
		    if(z>15){ shot = false; }
		    z++;
		    
	    }
	    
	    //draw duck
	    if(hit == true)
	    {
		    
		    //draw splat for 25 frames, and then draw a new duck
		    gc.drawImage(splat, xpos, ypos, 54, 54, null);
		    if(z>25)
	   		{
			    hit = false;
			    
			    //new random image
			    setRandomDuckImage();
			    		
			    //put new duck on screen
			    xvel=1+rand.nextInt(2);
			    yvel=1+rand.nextInt(2);
			    if(xvel==1)
			    { xvel=-2; dImg=1; }
			    else{ xvel=2; dImg=0; }
			    if(yvel==1)
			    { yvel=-2; }
			    else{ yvel=2; }
	    	}
	    	z++;
	    }
	    else
	    {
		    if(counter<6)
		    {
			    //if(duckx>=750){xvel=-xvel; dImg=1; counter++;}
			    //if(ducky>=480){yvel=-yvel; counter++;}
			    if(duckx>=xRes-dsizex){xvel=-xvel; dImg=1; counter++;}
			    if(ducky>=yRes-dsizey){yvel=-yvel; counter++;}
			    if(duckx<=0){xvel=-xvel; dImg=0; counter++;}
			    if(ducky<=0){yvel=-yvel; counter++;}
			    //dsizex=76;
			    //dsizey=37;
		    }
		    else
	    	{
			    xvel=0;
			    yvel=-2;
			    dImg=2;
			    //dsizex=75;
			    //dsizey=68;
			    if(ducky<=0)
			    {
				    // duck flew away
				    flewAwayFrameCounter++;
				    lastMessage = "It flew away. Score -10";
				    
				    //only decrease score during first frame
				    if (score > 0 && flewAwayFrameCounter == 1)
				    {
				    	score-=10;
				    }	
				    
				    
				    //create a new duck after 150 frames
				    if(p>150)
			    	{
			    		
			    		//new random image
			    		setRandomDuckImage();
			    		
			    		//put new duck on screen
			    		flewAwayFrameCounter = 0;
					    //duckx=10+rand.nextInt(705);
					    //ducky=10+rand.nextInt(460);
					    duckx=10+rand.nextInt(xRes-dsizex-10);
					    ducky=10+rand.nextInt(yRes-dsizey-10);
					    xvel=1+rand.nextInt(2);
					    yvel=1+rand.nextInt(2);
					    if(xvel==2)
					    { xvel=-2; dImg=1; }
					    else{ xvel=2; dImg=0; }
					    if(yvel==2)
					    { yvel=-2; }
					    else{ yvel=2; }
					    counter=0;
					    p=0;
					    esc++;
			    	}
			    	p++;
			    }
	    	}
		    duckx += xvel;
		    ducky += yvel;
		    gc.drawImage(ducks[dImg], duckx, ducky, dsizex, dsizey, null);
		    duckLoc = new Rectangle( duckx, ducky, dsizex, dsizey);
	    }
    }
    
    // Mouse functions:
    public void mouseMoved( MouseEvent e )
    {
	    x = e.getX();
	    y = e.getY();
    }
     
    public void mouseReleased( MouseEvent e ) 
    {
	    if( ( e.getButton() == e.BUTTON2 ) || ( e.getButton() == e.BUTTON3 ) )
	    {
		    ammo = 3;
		    sounda.play();
		    
	    }
	    else if( ammo>0 )
	    {
		    shot=true;
		    sound.play();
		    shots++;
		    xpos=x-27;
		    ypos=y-27;
		    z=0;
		    ammo--;
		    if(duckLoc.contains( e.getX(), e.getY() ) )
		    {
			    hit=true;
			    soundb.play();
			    hits++;
			    shot=false;
			    int lastCounter = counter; // keep the last counter to calculate the score
			    counter=0;
			    killScore++;
			    
			    /* increase speed after a specified number of kills */
			    if ((killScore % increasePerKill == 0) && (level < 20))
			    {
			    	speed--;
			    	level++;
			    	int levelincrease = 1000 * level;
			    	score+=levelincrease;
			    	lastMessage = "Level up! Score +"+levelincrease;
			    	// new background
			    	bg = Toolkit.getDefaultToolkit().getImage( "images/level"+level+".png" );
			    	//new music
			    	java.io.File musicFile = new java.io.File("music/music"+level+".mid");
	    			try{
	    				music.stop();
	    				music = Applet.newAudioClip(musicFile.toURL());
	    				music.loop();
	    			} catch (Exception ex){
	    				System.out.println("musicfile exception");
	    			}
			    }else{
			    	
			    	//just the points for the duck
			    	int levelmodifier = level; // multiply score based on level
			    	int countermodifier = 6 - lastCounter; // the earlier you shoot, the higher your score
			    	if (countermodifier < 1) { countermodifier = 1; }
			    	int scoreincrease = 20 * levelmodifier * countermodifier;
			    	score+=scoreincrease;
			    	lastMessage = "Kill! Score +"+scoreincrease;
			    	
			    }
			    
			    
			    //duckx=10+rand.nextInt(790);
			    //ducky=10+rand.nextInt(460);
			    duckx=10+rand.nextInt(xRes-dsizex-10);
			    ducky=10+rand.nextInt(yRes-dsizey-10);
		    }
	    }
	    else{ soundc.play(); }
    }//left click
    
    public void mouseDragged( MouseEvent e ) { }
    public void mouseEntered( MouseEvent e ) { }
    public void mouseExited( MouseEvent e ) { }
    public void mousePressed( MouseEvent e ) { }
    public void mouseClicked( MouseEvent e ) { }
    
    public static void main(String[] args) throws Exception
    {
	    java.io.File file = new java.io.File("sound/shotgun.wav");
	    AudioClip sound = Applet.newAudioClip(file.toURL() );
	    
	    java.io.File file1 = new java.io.File("sound/cockgun.wav");
	    AudioClip sounda = Applet.newAudioClip(file1.toURL() );
	    
	    java.io.File file2 = new java.io.File("sound/duck_1.wav");
	    AudioClip soundb = Applet.newAudioClip(file2.toURL() );
	    
	    java.io.File file3 = new java.io.File("sound/emptychamber.wav");
	    AudioClip soundc = Applet.newAudioClip(file3.toURL() );
	    
	    java.io.File file4 = new java.io.File("sound/toasty.wav");
	    AudioClip toasty = Applet.newAudioClip(file4.toURL() );
	    
	    //preload music
	    java.io.File musicFile = new java.io.File("music/music1.mid");
	    AudioClip music = Applet.newAudioClip(musicFile.toURL());
	    
	    
	    
	    DuckHunt egg = new DuckHunt(sound, sounda, soundb, soundc,toasty,music);
    }
    
    public void setRandomDuckImage()
    {
    	Random randomGenerator = new Random();
    	int randomInt = randomGenerator.nextInt(imageList.length);
    	
    	ducks[0] = Toolkit.getDefaultToolkit().getImage("images/"+ imageList[randomInt]+"1.png");
    	ducks[1] = Toolkit.getDefaultToolkit().getImage("images/"+ imageList[randomInt]+"2.png");
    	ducks[2] = Toolkit.getDefaultToolkit().getImage("images/"+ imageList[randomInt]+"3.png");
    	 
    }
    
    /*public void playRandomSound()
    {
    	Random randomGenerator = new Random();
    	int randomInt = randomGenerator.nextInt(imageList.length);
    	
    	ducks[0] = Toolkit.getDefaultToolkit().getImage("images/"+ imageList[randomInt]+"1.png");
    	ducks[1] = Toolkit.getDefaultToolkit().getImage("images/"+ imageList[randomInt]+"2.png");
    	ducks[2] = Toolkit.getDefaultToolkit().getImage("images/"+ imageList[randomInt]+"3.png");
    	 
    }*/
    
   

}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s