import java.awt.Color; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.event.KeyEvent; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.SourceDataLine; import javax.swing.JApplet; public class K4usality extends JApplet implements Runnable { private static final int MAP_SIZE = 15; private static final int TILE_SIZE = 32; private static final int SAMPLE_RATE = 44100; private static final int BUFFER_SIZE = 1024; private static final int MOVE_FRAMES = 16; private static final AudioFormat FORMAT = new AudioFormat(SAMPLE_RATE, 16, 1, true, true); private boolean moving; private final int[][][] charMoves = new int[4][1000][2]; // x y dir moveStep private final int[][] chars = new int[4][4]; private final boolean[] charActive = new boolean[4]; public K4usality() { } public void start(){ Thread t = new Thread(this); t.start(); } public void processKeyEvent(KeyEvent ke) { if (ke.getKeyCode() == 10){ // Enter } else if (ke.getKeyCode() >= 37 && ke.getKeyCode() <= 40){ if (chars[0][3] == 0){ switch (ke.getKeyCode()){ case 37: // LEFT chars[0][2] = 0; break; case 38: // UP chars[0][2] = 2; break; case 39: // RIGHT chars[0][2] = 1; break; case 40: // DOWN chars[0][2] = 3; break; } moving = ke.getID() == KeyEvent.KEY_PRESSED; } if (ke.getID() == KeyEvent.KEY_RELEASED){ moving = false; } } } private final static int clamp(int val, int min, int max){ if (val < min) return min; if (val > max) return max; return val; } public void run() { int i,j; int synthStep = 0; int seqStep = 0; final float NOTE_FREQUENCY[] = new float[32]; final String SONG = "\u0000\u0000\u0000\u0000\u0000\u0000\ua064\u9818\u8813\u8800\u0280\u03c0\u04c0\u03c0\u0300\u03c0\u04c0\u03c0\u0280\u03c0\u04c0\u53c9\ua364\u9bd8\u8cd3\u8bc0\u0280\u9be4\u04c0\u03c0\u7b13\u03c0\u8cdc\u53c9\u0280\u03c0\u04c0\u03c0\u0300\u03c0\u04c0\u53c9\u8b13\u0440\u9d1c\ua460\u0300\u0440\u8d1c\u7452\u0280\u0440\u7d13\u8c58\u0280\u0440\u5511\u5440\u0280\u9be3\u04c0\u03c0\u0300\u03c0\u04c0\u03c0\u0280\u03c0\u04c0\u03c0\ua324\u9bd8\u8cd3\u8bc0\u0280\u03c0\u04c0\u03c0\u0300\u03c0\u04c0\u03c0\u0280\u03c0\u04c0\u53c9\ua324\u9bd8\u8cd3\u8bc0\u0280\u03e0\u9cc4\u7bd3\u0300\u03c0\u8cdc\u53c9\u0280\u03c0\u04c0\u03c0\u0300\u03c0\u04c0\u03c0\u8b13\u0440\u9d1c\ua460\u0300\u0440\u8d13\u7449\u0280\u0440\u7d12\u8c58\u0280\u5449\u7d10\u8c58\u92e4\u8bd8\u7c90\u6809\u0000\u0000\u5009\u5810\u6b5b\u0340\u9364\u0000\u8b5b\u7b52\u7b40\u6808\u7ad2\u6ac9\u6ac0\u0440\u6a89\u0340\u5289\u5810\u6b5a\u0340\u935b\u0000\ua364\u9358\u8b51\u7808\u7ac0\u8ad2\u92d8\u0440\u928a\u0340\ua293\ub018\uba24\u0500\ub21b\u0500\ua212\u0340\u9209\ua518\ub363\ub340\ua35a\u0000\u9290\u03c0\u7a91\u6808\u7ad1\u92dc\u92c0\u8d13\u0280\u8a93\u9a9c\u9800\u0280\u03c0\u04c0\u03c0\u0300\u0200\u01c0\u00c0\u0000\u0000\u0000\u0000"; final Polygon HAIR = new Polygon(new int[]{-8,-4,1,6,8,2,-2,-6}, new int[]{-6,-14,-15,-12,-5,-6,-4,-7},8); final Color[] COLOURS = new Color[]{new Color(244,228,215), new Color(0,0,64)}; final byte[] sampleBuffer = new byte[BUFFER_SIZE*2]; long lastTime = System.nanoTime(); int state = 0; int absTime = 0; // 0 = FLOOR // 1 = WALL // 2 = STAIRS_DOWN // 3 = DOOR_CLOSED // 4 = BUTTON // // 6 = PORTAL // 8 = DOOR_OPEN final int[][] map = new int[][] { {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,1,0,0,0,0,0,0,1}, {1,0,0,6,0,0,0,1,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,1,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,1,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,1,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,1,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,3,0,0,0,0,0,2,1}, {1,0,0,0,0,0,0,1,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,1,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,1,0,0,0,0,0,0,1}, {1,0,0,4,0,0,0,1,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,1,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,1,0,0,0,0,0,0,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, }; int charCount = 1; int moveCount = 0; SourceDataLine dest = null; try { dest = AudioSystem.getSourceDataLine(FORMAT,AudioSystem.getMixer(null).getMixerInfo()); dest.open(FORMAT, sampleBuffer.length * 16); dest.start(); } catch (Exception e) {e.printStackTrace();} for(i = 0; i < NOTE_FREQUENCY.length; i++){ NOTE_FREQUENCY[i] = (float)(220*Math.pow(2.0,(i-12)/12.0)); } float lastSample = 0; BufferedImage backBuffer = new BufferedImage(640,480, 2); enableEvents(8); chars[0][0] = 7; chars[0][1] = 1; moveCount = 1; charMoves[0][0][0] = 0; charMoves[0][0][1] = ((0x01 << 24) | (chars[0][1] << 8) | chars[0][0]); for(i = 1; i < charMoves[0].length; i++){ charMoves[0][i][0] = Integer.MAX_VALUE; } while(true){ if (!this.hasFocus()){ requestFocus(); } // UPDATE if (moving && chars[0][3] == 0){ int x = chars[0][0]; int y = chars[0][1]; if ((chars[0][2] & 0x02) != 0){ int dy = (chars[0][2]&1)*2 - 1; if ((map[x][y + dy] & 1) == 0) chars[0][3] = 1; } else { int dx = (chars[0][2]&1)*2 - 1; if ((map[x + dx][y] & 1) == 0)chars[0][3] = 1; } if (chars[0][3] != 0){ charMoves[0][moveCount][0] = absTime; charMoves[0][moveCount++][1] = chars[0][2]; } } for(i = 1; i < charCount; i++){ for(j = 0; j < charMoves[i].length; j++){ if (charMoves[i][j][0] == absTime){ int moveType = charMoves[i][j][1]>>24; if (moveType == 0){ // Move chars[i][2] = charMoves[i][j][1]; chars[i][3] = 1; } else if (moveType == 1){ // Enter chars[i][0] = charMoves[i][j][1] & 0xFF; chars[i][1] = (charMoves[i][j][1]>>8) & 0xFF; charActive[i] = true; } break; } else if (charMoves[i][j][0] > absTime){ break; } } } for(i = 0; i < charCount; i++){ if (chars[i][3] > 0){ if (chars[i][3] == (MOVE_FRAMES-1)){ if ((chars[i][2] & 0x02) != 0){ int dy = (chars[i][2]&1)*2 - 1; chars[i][1] += dy; } else { int dx = (chars[i][2]&1)*2 - 1; chars[i][0] += dx; } chars[i][3] = 0; if (map[chars[i][0]][chars[i][1]] == 6){ if (i == 0){ int timeDelta = -60*10; // CHAR ENTERING PORTAL! //System.arraycopy(charMoves[0],0,charMoves[1],0,charMoves[0].length); for(j = charCount-1; j >= 0; j--){ for(int move = 0; move < charMoves[0].length; move++){ charMoves[j+1][move][0] = charMoves[j][move][0]; charMoves[j+1][move][1] = charMoves[j][move][1]; } } for(j = 0; j < charMoves[0].length; j++){ charMoves[0][j][0] = Integer.MAX_VALUE; } moveCount = 1; charCount++; absTime += timeDelta; charMoves[0][0][0] = absTime; charMoves[0][0][1] = (0x01 << 24) | (chars[0][1] << 8) | chars[0][0]; for(j = 1; j < charCount; j++){ charActive[j] = false; for(int move = 0; move < charMoves[0].length; move++){ if (charMoves[j][move][0] <= absTime){ int moveType = charMoves[j][move][1]>>24; if (moveType == 0){ // Move chars[j][2] = charMoves[j][move][1]; if ((chars[j][2] & 0x02) != 0){ int dy = (chars[j][2]&1)*2 - 1; chars[j][1] += dy; } else { int dx = (chars[j][2]&1)*2 - 1; chars[j][0] += dx; } if (map[chars[j][0]][chars[j][1]] == 6){ charActive[j] = false; } } else if (moveType == 1){ // Enter chars[j][0] = charMoves[j][move][1] & 0xFF; chars[j][1] = (charMoves[j][move][1]>>8) & 0xFF; charActive[j] = true; } } else { break; } } } } else { charActive[i] = false; } } } else { chars[i][3]++; } } } // DRAW Graphics2D g2d = (Graphics2D)backBuffer.getGraphics(); for(i = 0; i < MAP_SIZE; i++){ for(j = 0; j < MAP_SIZE; j++){ g2d.setColor(Color.GRAY); g2d.fill3DRect(i*TILE_SIZE,j*TILE_SIZE,TILE_SIZE,TILE_SIZE,true); if (map[i][j] == 2) { g2d.translate(i*32, j*32); Color c = Color.GRAY; for(int s = 0; s < 6; s++){ g2d.setColor(c); g2d.fillRect(4,24 - s*4,24 - s*2, 4); g2d.setColor(Color.BLACK); g2d.drawRect(4,24 - s*4,24 - s*2, 4); if (s%2 == 0){ c = c.darker(); } } g2d.setColor(Color.BLACK); g2d.drawRect(4,4,24,24); g2d.translate(-i*32, -j*32); } else if (map[i][j] == 1){ g2d.setColor(Color.WHITE); g2d.fillRect(i*TILE_SIZE,j*TILE_SIZE,TILE_SIZE,TILE_SIZE); if (j == MAP_SIZE - 1 || map[i][j+1] != 1){ g2d.setColor(Color.LIGHT_GRAY); g2d.fillRect(i*TILE_SIZE,j*TILE_SIZE+24,TILE_SIZE,8); } } else if (map[i][j] == 3){ g2d.setColor(Color.RED); g2d.fillRect(i*TILE_SIZE,j*TILE_SIZE+8,TILE_SIZE,16); g2d.setColor(Color.RED.darker()); g2d.fillRect(i*TILE_SIZE,j*TILE_SIZE+14,TILE_SIZE,10); } else if (map[i][j] == 4){ g2d.setColor(Color.DARK_GRAY); g2d.draw3DRect(i*TILE_SIZE+2,j*TILE_SIZE+4,28,24,true); g2d.setColor(Color.red.darker()); g2d.fillOval(i*TILE_SIZE+6,j*TILE_SIZE+8,20,16); g2d.setColor(Color.red.darker().darker()); g2d.drawOval(i*TILE_SIZE+6,j*TILE_SIZE+8,20,16); g2d.setColor(Color.red); g2d.fillOval(i*TILE_SIZE+6,j*TILE_SIZE+6,20,16); } else if (map[i][j] == 6){ g2d.setColor(Color.BLACK); g2d.fillOval(i*TILE_SIZE+8,j*TILE_SIZE+2,16,20); g2d.setColor(Color.BLUE); g2d.drawOval(i*TILE_SIZE+8,j*TILE_SIZE+2,16,20); } } } g2d.setColor(Color.BLACK); g2d.drawString(Integer.toString(absTime/60),128,16); AffineTransform tx = g2d.getTransform(); for(i = 0; i < charCount; i++){ if (!charActive[i] && i != 0){ continue; } int dt = (TILE_SIZE*chars[i][3])/MOVE_FRAMES; int dx = 0; int dy = 0; if ((chars[i][2] & 0x02) != 0){ dy = (chars[i][2]&1)*2 - 1; } else { dx = (chars[i][2]&1)*2 - 1; } g2d.translate(chars[i][0]*TILE_SIZE+16 + dx*dt,chars[i][1]*TILE_SIZE + 16 + dy*dt); // draw guy if (chars[i][2] == 3){ g2d.setColor(COLOURS[1]); g2d.fillRect(-6, 0, 6, 6); g2d.fillRect(0, 0, 6, 6); g2d.setColor(Color.WHITE); g2d.fillRect(-6, -4, 12, 8); g2d.setColor(COLOURS[0]); g2d.fillOval(-6, -14, 12, 14); g2d.fillRect(-10, -1, 3, 4); g2d.fillRect(7, -1, 3, 4); g2d.setColor(Color.WHITE); g2d.fillRect(-8, -2, 4, 4); g2d.fillRect(4, -2, 4, 4); g2d.setColor(Color.BLACK); g2d.fillPolygon(HAIR); g2d.drawLine(-6, -4, 6, -4); g2d.drawLine(0, 0, 0, 5); g2d.drawRect(-4, -4, 3, 2); g2d.drawRect(1, -4, 3, 2); g2d.drawOval(-6, -14, 12, 14); } else if (chars[i][2] == 2){ g2d.setColor(COLOURS[1]); g2d.fillRect(-6, 0, 6, 6); g2d.fillRect(0, 0, 6, 6); g2d.setColor(Color.WHITE); g2d.fillRect(-6, -4, 12, 8); g2d.setColor(COLOURS[0]); g2d.fillRect(-10, -1, 3, 4); g2d.fillRect(7, -1, 3, 4); g2d.setColor(Color.WHITE); g2d.fillRect(-8, -2, 4, 4); g2d.fillRect(4, -2, 4, 4); g2d.setColor(Color.BLACK); g2d.fillPolygon(HAIR); g2d.fillOval(-6, -14, 12, 14); } else { g2d.setColor(COLOURS[1]); g2d.fillRect(-4, 0, 8, 6); g2d.setColor(Color.WHITE); g2d.fillRect(-4, -4, 8, 8); g2d.setColor(COLOURS[0]); g2d.fillOval(-6, -14, 12, 14); g2d.fillRect(-2, -1, 3, 4); g2d.setColor(Color.BLACK); g2d.fillPolygon(HAIR); g2d.drawOval(-6, -14, 12, 14); } g2d.setTransform(tx); } getGraphics().drawImage(backBuffer,0,0,null); while(System.nanoTime() - lastTime < 16000000) Thread.yield(); lastTime = System.nanoTime(); // STEP THE SYNTH if (dest.available() > sampleBuffer.length){ int songStep = (seqStep/8)%SONG.length(); for(i = 0; i < sampleBuffer.length/2; i++){ float val = 0; int note = SONG.charAt(songStep); int key = songStep > 0? (note>>11) & 0x1F : 0; if (key != 0){ int index = (int)(synthStep*NOTE_FREQUENCY[key]); //int channel = (note >> 5) & 0x03; index %= SAMPLE_RATE; val += index < SAMPLE_RATE/2 ? 1.0f : - 1.0f; } key = songStep > 0 ? (note>>6) & 0x1F : 0; if (key != 0){ int index = (int)(synthStep*NOTE_FREQUENCY[key]); //int channel = (note >> 5) & 0x03; index %= SAMPLE_RATE; val += (index/((float)SAMPLE_RATE) - 0.5f); } val = val*0.1f + lastSample*0.99f; lastSample = val; short sample = (short)(val*0xFFF); sampleBuffer[i*2+1] = (byte)(sample & 0xFF); sampleBuffer[i*2] = (byte)((sample >> 8) & 0xFF); synthStep++; } dest.write(sampleBuffer,0,sampleBuffer.length); seqStep++; } absTime++; } } }