1kvaders

So for amusement’s sake I thought I’d see what kind of game fits into 1 kB of Java, given that about half of that seems to be taken up by overhead. This is what I managed to cram in:

http://www.metalbeetle.com/1kvaders.html

Click once to focus on applet. Then use arrow keys to move and space to fire. Don’t let the green blobs get to the bottom of the screen.

It’s fairly terrible, but just about qualifies as a game. (I won’t submit it to the official contest as it’s clearly terrible compared to what you can do with quadruple the space.)

That’s quite cool with only 1kb.

About 560 kB of that is just the scaffolding of having a main loop and keyboard input listeners. So 1 kB is probably about the lowest amount of memory you could have a competition on. A competition full of half-baked space invaders clones, simple driving games, and maybe tic-tac-toe?

I raise you Pong 1k ;D

The pack200 is 1023 bytes. I’ve linked to the jar, which is a bit bigger.

pack200 file: http://homepage.ntlworld.com/alan.d.waddington/java/competitions/java1k/Pong1k_kzip128.jar.pack.gz

Controls:

Click for Focus
Space to Start
X and S to control bat

Awesome! It’s a bit more of a game than mine. Can I have a look at the source code? Mine is here:

Actually I thought yours was better :smiley:

* Copyright 2011 Alan Waddington
 *
 * Controls
 * Up:    S
 * Down:  X
 * Start: SPACE
 */

import java.applet.Applet;
import java.awt.Color;
import java.awt.Event;
import java.awt.image.BufferedImage;
import java.awt.Graphics;

/** Play Pong */
public class P extends Applet implements Runnable {

    private final static int SCREENWIDTH  = 800;    // Applet size
    private final static int SCREENHEIGHT = 600;
    private final static int BATWIDTH     = 10;     // Bat dimensions
    private final static int BATHEIGHT    = 30;
    private final static int BALLSIZE     = 10;     // Ball diameter
    private final static int BATX         = 20;  // Bat indent from screen edge

    private final static float PLAYERSPEED   = 0.0002f;   // Player bat speed
    private final static float COMPUTERSPEED = 0.000186f; // Computer bat speed
    private final static float BALLSPEED     = 0.0002f;   // Ball Speed (X & Y)
    private final static int   WIN           = 3;         // Winning Score

    private static boolean input[] = new boolean[0x10000]; // Keyboard map

    /** Start Game */
    @Override
    public void start() {
        new Thread(this).start();
    }

    /** Game Thread */
    public void run() {

        // Initialisation
        float playerX0 = 0, playerY0 = 0;
        float playerX1 = 0, playerY1 = 0;
        float ballX = 0, ballY = 0;

        float ballSpeedX = BALLSPEED;
        float ballSpeedY = BALLSPEED;

        int playerScore = 0;
        int computerScore = 0;

        boolean gameOver = true;
        boolean reset = true;

        long time, lastTime;
        long deltaTime = 0;
        lastTime = time = System.nanoTime()/1000;

        // Create screen image (double buffer)
        BufferedImage screen = new BufferedImage(
            SCREENWIDTH, SCREENHEIGHT, BufferedImage.TYPE_INT_RGB);
        while(!isActive()) Thread.yield();  // Appletviewer workaround
        Graphics g = screen.getGraphics();
        Graphics gs = getGraphics();
        //requestFocus();

        // Game loop
        do {
            lastTime = time;
            time = System.nanoTime()/1000;
            deltaTime = time - lastTime;

            // Restart game
            if (reset) {
                reset = false;
                playerScore = 0;
                computerScore = 0;
                playerX0 = BATX-BATWIDTH;
                playerY0 = SCREENHEIGHT/2;
                playerX1 = SCREENWIDTH-BATX;
                playerY1 = SCREENHEIGHT/2;
                ballX = SCREENWIDTH/2;
                ballY = SCREENHEIGHT/2;
            }

            // Player Bat Position
            if (input['s'] && playerY0>0)
                playerY0-=PLAYERSPEED*deltaTime;
            if (input['x'] && playerY0<SCREENHEIGHT-BATHEIGHT)
                playerY0+=PLAYERSPEED*deltaTime;

            // Computer Bat Position
            if (playerY1+BATHEIGHT/2>ballY+BALLSIZE/2) {
                playerY1-=COMPUTERSPEED*deltaTime;
            }
            if (playerY1+BATHEIGHT/2<ballY+BALLSIZE/2) {
                playerY1+=COMPUTERSPEED*deltaTime;
            }

            // Move Ball
            if (!gameOver) {
                ballX += ballSpeedX*deltaTime;
                ballY += ballSpeedY*deltaTime;
            }
            // Collision Logic
            if (ballY<0) {                              // Top
                ballY = - ballY;
                ballSpeedY *=-1;
            }
            if (ballY>SCREENHEIGHT-BALLSIZE) {          // Bottom
                ballY = 2*(SCREENHEIGHT-BALLSIZE) - ballY;
                ballSpeedY *=-1;
            }
            if (ballX<playerX0+BATWIDTH &&             // Left (Bat)
                ballY-playerY0<BATHEIGHT+BALLSIZE &&
                playerY0-ballY<BALLSIZE) {
                ballX = 2*(playerX0+BATWIDTH) - ballX;
                ballSpeedX *=-1;
            }
            if (ballX+BALLSIZE>playerX1 &&              // Right (Bat)
                ballY-playerY1<BATHEIGHT+BALLSIZE &&
                playerY1-ballY<BALLSIZE) {
                ballX = 2*(playerX1-BALLSIZE) - ballX;
                ballSpeedX *=-1;
            }
            if (ballX<-BATWIDTH) {                      // Player misses
                computerScore++;
                ballX = SCREENWIDTH/2;
                ballY = SCREENHEIGHT/2;
                ballSpeedX *=-1;
            }
            if (ballX>SCREENWIDTH) {                    // Computer misses
                playerScore++;
                ballX = SCREENWIDTH/2;
                ballY = SCREENHEIGHT/2;
                ballSpeedX *=-1;
            }

            if (playerScore>=WIN || computerScore>=WIN) { // Detect game over
                gameOver = true;
            }

            // Draw bats and ball
            g.setColor(Color.BLACK);
            g.fillRect(0,0,SCREENWIDTH, SCREENHEIGHT);
            g.setColor(Color.GREEN);
            g.fillRect((int)playerX0, (int)playerY0, BATWIDTH, BATHEIGHT);
            g.fillRect((int)playerX1, (int)playerY1, BATWIDTH, BATHEIGHT);
            g.fillRect((int)ballX, (int)ballY, BALLSIZE, BALLSIZE);

            // Display Scores and messages
            //g.setFont(getFont().deriveFont(java.awt.Font.BOLD,20));
            g.drawString("["+String.valueOf(playerScore+"]"), SCREENWIDTH/4, 20);
            if (playerScore==WIN) {
                g.drawString("You Win",SCREENWIDTH/2-20,100);
            }
            g.drawString("["+String.valueOf(computerScore)+"]", SCREENWIDTH*3/4, 20);
            if (computerScore==WIN) {
                g.drawString("I Win",SCREENWIDTH/2-10,100);
            }
            if (gameOver) {
                g.drawString("Press SPACE",SCREENWIDTH/2-35,130);
                if (input[' ']) {
                    gameOver = false;
                    reset = true;
                }
            }

            // Update screen

            gs.drawImage(screen, 0,0,null);

            Thread.yield();
        } while (isActive());

    }

    /** Process Keyboard Events */
    @Override
    public boolean handleEvent(Event e) {
        input[e.key] = (e.id&1)==1;
        return false;
    }

}