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");
}*/
}