view game/Engine.java @ 21:df494a65bf8c

More work.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 31 Jan 2011 19:46:41 +0200
parents 4507a431b410
children afde253ec705
line wrap: on
line source

/*
 * Ristipolku Game Engine
 * (C) Copyright 2011 Matti 'ccr' Hämäläinen <ccr@tnsp.org>
 */
package game;

import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.imageio.*;
import javax.swing.*;
import java.util.*;
import java.io.*;
import game.*;

import javax.sound.sampled.*;


enum Sound
{
    PIECE_PLACED("placed.wav", true),

    MUSIC_GAME1("gamemusic.wav", false);


    private final String name;
    private final boolean effect;

    Sound(String name, boolean effect)
    {
        this.name = name;
        this.effect = effect;
    }

    public String getName()
    {
        return this.name;
    }
    
    public boolean isEffect()
    {
        return effect;
    }
}


class SoundElement implements Runnable
{
    private final String name;
    private Clip clip;
    private AudioInputStream stream;
    private AudioFormat format;
    private SourceDataLine line;
    private Thread playThread;
    private int loopCount;
    private boolean doPlay;
    
    SoundElement(String filename, boolean effect) throws IOException
    {
        this.name = filename;

        ResourceLoader res = new ResourceLoader(name);
        if (res == null || res.getStream() == null)
        {
            throw new IOException("Could not load audio resource '"+name+"'.\n");
        }

        try {
            stream = AudioSystem.getAudioInputStream(res.getStream());
        }
        catch (UnsupportedAudioFileException e) {
            throw new IOException("Unsupported audio file format for '"+name+"'.\n");
        }
        catch (IOException e)
        {
            throw new IOException("Could not load audio resource '"+name+"'.\n");
        }

        format = stream.getFormat();

        if (effect) {
            System.out.print("Loading '"+name+"' as a clip\n");
            try {
                clip = AudioSystem.getClip();
                clip.open(stream);
            }
            catch (LineUnavailableException e)
            {
                throw new IOException("Line unavailable for '"+name+"'.\n");
            }
            finally {
                stream.close();
            }
        }
        else
        {
            clip = null;
            System.out.print("Loading '"+name+"' as stream\n");
            
            try {
                SourceDataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
                System.out.print("info: "+stream.getFrameLength() + ", " + format.getFrameSize() + "\n");
                line = (SourceDataLine) AudioSystem.getLine(info);
                line.open(format);
            }
            catch (LineUnavailableException e) {
                throw new IOException("Line unavailable for '"+name+"'.\n");
            }
        }
    }

    public boolean isClip()
    {
        return (clip != null && line == null);
    }

    public void play()
    {
        System.out.print("Sound("+name+").play()\n");
        if (isClip())
        {
            clip.setFramePosition(0);
            clip.start();
        }
        else
        {
            if (playThread == null)
            {
                doPlay = true;
                loopCount = 1;
                playThread = new Thread(this);
                playThread.start();
            }
        }
    }
    
    public void loop(int n)
    {
        System.out.print("Sound("+name+").loop("+n+")\n");
        if (isClip())
        {
            clip.setFramePosition(0);
            if (n < 0)
                clip.loop(Clip.LOOP_CONTINUOUSLY);
            else
                clip.loop(n);
        }
        else
        {
            if (playThread == null)
            {
                doPlay = true;
                loopCount = n;
                playThread = new Thread(this);
                playThread.start();
            }
        }
    }
    
    public void stop()
    {
        if (isClip())
        {
            if (clip.isRunning())
                clip.stop();
        }
        else
        {
            if (playThread != null)
            {
                playThread.interrupt();
                doPlay = false;
                playThread = null;
            }
        }
    }
    
    public boolean isPlaying()
    {
        if (isClip())
            return clip.isRunning();
        else
            return (playThread != null && doPlay);
    }

    public void run()
    {
        line.start();
        byte[] buf = new byte[line.getBufferSize()];

        while (doPlay && (loopCount > 0 || loopCount == -1))
        {
            try {
                int numRead = 0;
                while ((numRead = stream.read(buf, 0, buf.length)) >= 0 && doPlay)
                {
                    int offset = 0;
                    while (offset < numRead)
                    {
                        System.out.print("audioThread: offs="+offset+", numread="+numRead+"\n");
                        offset += line.write(buf, offset, numRead - offset);
                    }
                }
                line.drain();

                System.out.print("audioThread: stream.reset()\n");
                stream.reset();
            }
            catch (IOException e) {
            }

            if (loopCount > 0)
                loopCount--;
        }
        
        line.stop();
        doPlay = false;
    }
}


class PathInfo
{
    public int in, inX, inY, out, outX, outY; 
   
    public PathInfo(int in, int inX, int inY, int out, int outX, int outY)
    {
        this.in = in;
        this.inX = inX;
        this.inY = inY;

        this.out = out;
        this.outX = outX;
        this.outY = outY;
    }
}

/*
class AnimatedElement
{
    float x, y, stime, value;
    Interpolate lerp;
    boolean active;
    
    public AnimatedElement(float x, float y, )
    {
        stime = 0;
        this.x = x;
        this.y = y;
        
    }
    
    public animate(float time)
    {
        if (!active)
        {
            active = true;
            stime = time;
        }
        
        float t = (time - stime) / 10.0f;
        if (t < 100)
            value = lerp.getValue(t);
        else
        {
            
        }
    }
    
    public paint(Graphics2D g, );
    {
    }
}
*/

class GameBoard
{
    public static final int boardSize = 9;
    public static final int boardMiddle = 4;
    Piece[][] board;
    Piece current;
    public boolean flagGameOver;
    
    int moveX, moveY, movePoint;

    public GameBoard()
    {
        board = new Piece[boardSize][boardSize];

        board[boardMiddle][boardMiddle] = new Piece(PieceType.START);

        moveX = boardMiddle;
        moveY = boardMiddle - 1;
        movePoint = 0;
        
        pieceFinishTurn();        
        
        flagGameOver = false;
    }

    public void paint(Graphics2D g, int sx, int sy, float scale)
    {
        for (int y = 0; y < boardSize; y++)
        for (int x = 0; x < boardSize; x++)
        if (board[x][y] != null)
        {
            AffineTransform save = g.getTransform();

            board[x][y].paint(g,
                sx + (x * scale),
                sy + (y * scale),
                scale - scale / 10);

            g.setTransform(save);
        }
    }
    
    public void animate(float time)
    {
        for (int y = 0; y < boardSize; y++)
        for (int x = 0; x < boardSize; x++)
        if (board[x][y] != null)
        {
            board[x][y].animate(time);
        }

    }
   
    private boolean isEmpty(int x, int y)
    {
        return (x >= 0 && x < boardSize && y >= 0 && y < boardSize && board[x][y] == null);
    }

    private Piece getPiece(int x, int y)
    {
        if (x >= 0 && x < boardSize && y >= 0 && y < boardSize)
            return board[x][y];
        else
            return null;
    }

    public void pieceRotate(boolean dir)
    {
        if (current != null)
            current.rotate(dir);
    }

    public PathInfo resolvePath(int startX, int startY, int startPoint, boolean mark)
    {
        int x = startX, y = startY;
        int point = -1;

        Piece curr = getPiece(startX, startY);
        if (curr == null)
            return null;

/*            
        while (curr != null)
        {
//            curr.(true);
//            elements.spawn("", );
        }
*/
      
        return new PathInfo(startPoint, startX, startY, point, x, y);
    }

    public void pieceFinishTurn()
    {
        if (current != null)
        {
            current.setType(PieceType.LOCKED);
            PathInfo i = resolvePath(moveX, moveY, movePoint, true);
            
            if (i != null)
            {
            }
        }

        current = new Piece(PieceType.ACTIVE);
        if (isEmpty(moveX, moveY))
        {
            board[moveX][moveY] = current;
        }
        else
        {
            PathInfo i = resolvePath(moveX, moveY, movePoint, true);
            if (i != null)
                board[moveX][moveY] = current;
            else
                flagGameOver = true;
        }
   }
}


public class Engine extends JPanel
                    implements Runnable, KeyListener, MouseListener
{
    Thread animThread;
    boolean animEnable = false;
    GameBoard lauta = null;
    BufferedImage lautaBG = null, lautaBGScaled = null;
    Dimension oldDim;
    float clock;
    SoundElement[] sounds;

    public SoundElement snd(Sound snd)
    {
        return sounds[snd.ordinal()];
    }

    public Engine()
    {
        BufferedImage img;
        clock = 0;

        System.out.print("Engine() constructor\n");

        try
        {
            ResourceLoader res = new ResourceLoader("graphics/board.png");
            lautaBG = ImageIO.read(res.getStream());

            sounds = new SoundElement[16];
            for (Sound s : Sound.values())
            {
                System.out.print(s +" = "+ s.ordinal() +"\n");
                sounds[s.ordinal()] = new SoundElement("sounds/" + s.getName(), s.isEffect());
            }
        }
        catch (IOException e)
        {
/*
            JOptionPane.showMessageDialog(null,
                e.getMessage(),
                "Initialization error",
                JOptionPane.ERROR_MESSAGE);
*/
            System.out.print(e.getMessage());
        }

        lauta = new GameBoard();
        addKeyListener(this);
        addMouseListener(this);

        // Get initial focus
        if (!hasFocus())
        {
            System.out.print("Engine(): requesting focus\n");
            requestFocus();
        }
        
        snd(Sound.MUSIC_GAME1).loop(-1);
//        snd(Sound.PIECE_PLACED).loop(-1);
    }

    public void startThreads()
    {
        System.out.print("startThreads()\n");
        if (animThread == null)
        {
            animThread = new Thread(this);
            animEnable = true;
            animThread.start();
        }
    }
    
    public void stopThreads()
    {
        System.out.print("stopThreads()\n");
        if (animThread != null)
        {
            animThread.interrupt();
            animEnable = false;
            animThread = null;
        }
    }

    public void mousePressed(MouseEvent e) { }
    public void mouseEntered(MouseEvent e) { }
    public void mouseExited(MouseEvent e) { }
    public void mouseReleased(MouseEvent e) { }

    public void mouseClicked(MouseEvent e)
    {
        System.out.print("mouseClicked()\n");
        if (!hasFocus())
        {
            System.out.print("requesting focus\n");
            requestFocus();
        }
    }

    public void paintComponent(Graphics g)
    {
        Graphics2D g2 = (Graphics2D) g;
        
        // Use antialiasing when rendering the game elements
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);

        // Rescale background if component size has changed
        Dimension dim = getSize();
        if (oldDim == null || !dim.equals(oldDim))
        {
            lautaBGScaled = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
            Graphics2D gimg = lautaBGScaled.createGraphics();
            gimg.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                                  RenderingHints.VALUE_INTERPOLATION_BICUBIC);

            gimg.drawImage(lautaBG, 0, 0, dim.width, dim.height, null); 
            oldDim = dim;
            System.out.print("scale changed\n");
        }
        
        // Background, pieces
        g2.drawImage(lautaBGScaled, 0, 0, null);
        lauta.paint(g2, 100, 150, 60);

        // Other elements
    }

    public void keyTyped(KeyEvent e)
    {
    }
   
    public void keyReleased(KeyEvent e)
    {
    }
   
    public void keyPressed(KeyEvent e)
    {
        System.out.print("running "+ snd(Sound.MUSIC_GAME1) + "\n");
        switch (e.getKeyCode())
        {
            case KeyEvent.VK_LEFT:
            case KeyEvent.VK_UP:
                lauta.pieceRotate(false);
                break;

            case KeyEvent.VK_RIGHT:
            case KeyEvent.VK_DOWN:
                lauta.pieceRotate(true);
                break;

            case KeyEvent.VK_ENTER:
                lauta.pieceFinishTurn();
                snd(Sound.PIECE_PLACED).stop();
                snd(Sound.PIECE_PLACED).play();
                break;
        }
    }
    
    public void run()
    {
        while (animEnable)
        {
            clock++;
            
//            System.out.print("clock=" + clock + "\n");

            lauta.animate(clock);
            
            if (clock % 2 == 1)
                repaint();
            
            try {
                Thread.sleep(10);
            }

            catch (InterruptedException x) {
            }
        }
    }
}