342 lines
8.0 KiB
Java
342 lines
8.0 KiB
Java
package dk.itu.mario.engine;
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Dimension;
|
|
import java.awt.Graphics;
|
|
import java.awt.GraphicsConfiguration;
|
|
import java.awt.Point;
|
|
import java.awt.Rectangle;
|
|
import java.awt.Robot;
|
|
import java.awt.event.FocusEvent;
|
|
import java.awt.event.FocusListener;
|
|
import java.awt.event.KeyEvent;
|
|
import java.awt.event.KeyListener;
|
|
import java.awt.event.MouseEvent;
|
|
import java.awt.event.MouseListener;
|
|
import java.awt.image.BufferedImage;
|
|
import java.awt.image.VolatileImage;
|
|
import java.io.File;
|
|
import java.util.Random;
|
|
|
|
import javax.imageio.ImageIO;
|
|
import javax.sound.sampled.LineUnavailableException;
|
|
import javax.swing.JComponent;
|
|
|
|
import dk.itu.mario.MarioInterface.LevelGenerator;
|
|
import dk.itu.mario.engine.sonar.FakeSoundEngine;
|
|
import dk.itu.mario.engine.sonar.SonarSoundEngine;
|
|
import dk.itu.mario.engine.sprites.Mario;
|
|
import dk.itu.mario.scene.LevelScene;
|
|
import dk.itu.mario.scene.LevelSceneCustom;
|
|
import dk.itu.mario.scene.LoseScene;
|
|
import dk.itu.mario.scene.Scene;
|
|
import dk.itu.mario.scene.WinScene;
|
|
|
|
public class MarioComponent extends JComponent implements Runnable,
|
|
KeyListener, FocusListener, MouseListener {
|
|
|
|
private static final long serialVersionUID = 739318775993206607L;
|
|
public static final int TICKS_PER_SECOND = 24;
|
|
public static final int EVOLVE_VERSION = 4;
|
|
public static final int GAME_VERSION = 4;
|
|
|
|
private boolean running = false;
|
|
private boolean screenshotTaken = false;
|
|
private boolean useScale2x = false;
|
|
private boolean isCustom = false;
|
|
private int width, height;
|
|
private GraphicsConfiguration graphicsConfiguration;
|
|
private LevelGenerator levelGenerator;
|
|
private Scene scene;
|
|
private SonarSoundEngine sound;
|
|
private Scale2x scale2x = new Scale2x(320, 240);
|
|
|
|
public MarioComponent(int width, int height, boolean isCustomized,
|
|
LevelGenerator levelGenerator) {
|
|
addFocusListener(this);
|
|
addMouseListener(this);
|
|
addKeyListener(this);
|
|
|
|
this.setFocusable(true);
|
|
this.setEnabled(true);
|
|
this.width = width;
|
|
this.height = height;
|
|
this.isCustom = isCustomized;
|
|
|
|
Dimension size = new Dimension(width, height);
|
|
setPreferredSize(size);
|
|
setMinimumSize(size);
|
|
setMaximumSize(size);
|
|
|
|
try {
|
|
sound = new SonarSoundEngine(64);
|
|
} catch (LineUnavailableException e) {
|
|
e.printStackTrace();
|
|
sound = new FakeSoundEngine();
|
|
}
|
|
this.setFocusable(true);
|
|
this.levelGenerator = levelGenerator;
|
|
LevelScene.bothPlayed = false;
|
|
}
|
|
|
|
private void toggleKey(int keyCode, boolean isPressed) {
|
|
if (scene == null) {
|
|
return;
|
|
}
|
|
if (keyCode == KeyEvent.VK_LEFT) {
|
|
scene.toggleKey(Mario.KEY_LEFT, isPressed);
|
|
}
|
|
if (keyCode == KeyEvent.VK_RIGHT) {
|
|
scene.toggleKey(Mario.KEY_RIGHT, isPressed);
|
|
}
|
|
if (keyCode == KeyEvent.VK_DOWN) {
|
|
scene.toggleKey(Mario.KEY_DOWN, isPressed);
|
|
}
|
|
if (keyCode == KeyEvent.VK_UP) {
|
|
scene.toggleKey(Mario.KEY_UP, isPressed);
|
|
}
|
|
if (keyCode == KeyEvent.VK_A) {
|
|
scene.toggleKey(Mario.KEY_SPEED, isPressed);
|
|
}
|
|
if (keyCode == KeyEvent.VK_S) {
|
|
scene.toggleKey(Mario.KEY_JUMP, isPressed);
|
|
}
|
|
if (keyCode == KeyEvent.VK_ENTER) {
|
|
scene.toggleKey(Mario.KEY_ENTER, isPressed);
|
|
}
|
|
if (isPressed && keyCode == KeyEvent.VK_F1) {
|
|
useScale2x = !useScale2x;
|
|
}
|
|
if (keyCode == KeyEvent.VK_D) {
|
|
if (!isPressed) {
|
|
screenshotTaken = false;
|
|
} else if (!screenshotTaken) {
|
|
screenshotTaken = true;
|
|
takeScreenShot();
|
|
}
|
|
}
|
|
|
|
if (isPressed && keyCode == KeyEvent.VK_ESCAPE) {
|
|
try {
|
|
System.exit(1);
|
|
} catch (Exception e) {
|
|
System.out.println("Unable to exit.");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void takeScreenShot() {
|
|
System.out.println("Taking screenshot.");
|
|
Point loc = getLocationOnScreen();
|
|
|
|
Rectangle screenRect = new Rectangle(loc.x, loc.y, getWidth(), getHeight());
|
|
|
|
try {
|
|
|
|
Robot robot = new Robot();
|
|
BufferedImage bufferedImg = robot.createScreenCapture(screenRect);
|
|
File tempFile = File.createTempFile("screenshot", ".png", new File("."));
|
|
ImageIO.write(bufferedImg, "png",
|
|
tempFile);
|
|
System.out.println("Screeshot saved to current working directory: " + tempFile.getName());
|
|
} catch (Exception ex) {
|
|
ex.printStackTrace(System.out);
|
|
}
|
|
}
|
|
|
|
public void paint(Graphics g) {
|
|
super.paint(g);
|
|
}
|
|
|
|
public void update(Graphics g) {
|
|
}
|
|
|
|
public void start() {
|
|
if (!running) {
|
|
running = true;
|
|
new Thread(this, "Game Thread").start();
|
|
}
|
|
}
|
|
|
|
public void stop() {
|
|
Art.stopMusic();
|
|
running = false;
|
|
}
|
|
|
|
public void run() {
|
|
|
|
graphicsConfiguration = getGraphicsConfiguration();
|
|
|
|
Art.init(graphicsConfiguration, sound);
|
|
|
|
VolatileImage image = createVolatileImage(320, 240);
|
|
Graphics g = getGraphics();
|
|
Graphics og = image.getGraphics();
|
|
|
|
int lastTick = -1;
|
|
|
|
long startTime = System.nanoTime();
|
|
|
|
float time = (System.nanoTime() - startTime) / 1000000000f;
|
|
float now = time;
|
|
float averagePassedTime = 0;
|
|
|
|
boolean naiveTiming = true;
|
|
|
|
// /Not sure I understand the weird dichotomy between LevelScene and
|
|
// LevelInterface...
|
|
randomLevel = new LevelSceneCustom(graphicsConfiguration, this,
|
|
new Random().nextLong(), 0, 0, isCustom, levelGenerator);
|
|
|
|
Mario.fire = false;
|
|
Mario.large = false;
|
|
Mario.coins = 0;
|
|
Mario.lives = 3;
|
|
|
|
randomLevel.init();
|
|
randomLevel.setSound(sound);
|
|
scene = randomLevel;
|
|
// /
|
|
|
|
while (running) {
|
|
float lastTime = time;
|
|
time = (System.nanoTime() - startTime) / 1000000000f;
|
|
float passedTime = time - lastTime;
|
|
|
|
if (passedTime < 0)
|
|
naiveTiming = false; // Stop relying on nanotime if it starts
|
|
// skipping around in time (ie running
|
|
// backwards at least once). This
|
|
// sometimes happens on dual core amds.
|
|
averagePassedTime = averagePassedTime * 0.9f + passedTime * 0.1f;
|
|
|
|
if (naiveTiming) {
|
|
now = time;
|
|
} else {
|
|
now += averagePassedTime;
|
|
}
|
|
|
|
int tick = (int) (now * TICKS_PER_SECOND);
|
|
|
|
if (lastTick == -1)
|
|
lastTick = tick;
|
|
|
|
while (lastTick < tick) {
|
|
scene.tick();
|
|
|
|
lastTick++;
|
|
}
|
|
|
|
float alpha = (float) (now * TICKS_PER_SECOND - tick);
|
|
sound.clientTick(alpha);
|
|
|
|
og.setColor(Color.WHITE);
|
|
og.fillRect(0, 0, 320, 240);
|
|
|
|
scene.render(og, alpha);
|
|
|
|
if (!this.hasFocus() && tick / 4 % 2 == 0) {
|
|
String msg = "CLICK TO PLAY";
|
|
|
|
drawString(og, msg, 160 - msg.length() * 4 + 1, 110 + 1, 0);
|
|
drawString(og, msg, 160 - msg.length() * 4, 110, 7);
|
|
}
|
|
og.setColor(Color.BLACK);
|
|
|
|
if (width != 320 || height != 240) {
|
|
|
|
if (useScale2x) {
|
|
g.drawImage(scale2x.scale(image), 0, 0, null);
|
|
} else {
|
|
g.drawImage(image, 0, 0, 640, 480, null);
|
|
|
|
}
|
|
} else {
|
|
g.drawImage(image, 0, 0, null);
|
|
}
|
|
|
|
try {
|
|
Thread.sleep(5);
|
|
} catch (InterruptedException e) {
|
|
}
|
|
}
|
|
|
|
Art.stopMusic();
|
|
}
|
|
|
|
private void drawString(Graphics g, String text, int x, int y, int c) {
|
|
char[] ch = text.toCharArray();
|
|
for (int i = 0; i < ch.length; i++) {
|
|
g.drawImage(Art.font[ch[i] - 32][c], x + i * 8, y, null);
|
|
}
|
|
}
|
|
|
|
public void keyPressed(KeyEvent arg0) {
|
|
toggleKey(arg0.getKeyCode(), true);
|
|
}
|
|
|
|
public void keyReleased(KeyEvent arg0) {
|
|
toggleKey(arg0.getKeyCode(), false);
|
|
}
|
|
|
|
public void keyTyped(KeyEvent arg0) {
|
|
}
|
|
|
|
public void focusGained(FocusEvent arg0) {
|
|
}
|
|
|
|
public void focusLost(FocusEvent arg0) {
|
|
}
|
|
|
|
public void levelWon() {
|
|
}
|
|
|
|
public static final int OPTIMIZED_FIRST = 0;
|
|
public static final int MINIMIZED_FIRST = 1;
|
|
|
|
private LevelScene randomLevel;
|
|
|
|
public void lose() {
|
|
scene = new LoseScene();
|
|
scene.setSound(sound);
|
|
scene.init();
|
|
}
|
|
|
|
public void win() {
|
|
scene = new WinScene();
|
|
scene.setSound(sound);
|
|
scene.init();
|
|
}
|
|
|
|
public void mouseClicked(MouseEvent e) {
|
|
}
|
|
|
|
public void mouseEntered(MouseEvent e) {
|
|
// TODO Auto-generated method stub
|
|
}
|
|
|
|
public void mouseExited(MouseEvent e) {
|
|
// TODO Auto-generated method stub
|
|
}
|
|
|
|
public void mousePressed(MouseEvent e) {
|
|
// TODO Auto-generated method stub
|
|
}
|
|
|
|
public void mouseReleased(MouseEvent e) {
|
|
|
|
while (!hasFocus()) {
|
|
System.out.println("FORCE IT");
|
|
requestFocus();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Must return the actual fill of the viewable components
|
|
*/
|
|
public Dimension getPreferredSize() {
|
|
return new Dimension(width, height);
|
|
}
|
|
|
|
}
|