Files
cs8803p4/src/dk/itu/mario/scene/LevelScene.java

602 lines
15 KiB
Java

package dk.itu.mario.scene;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import dk.itu.mario.engine.Art;
import dk.itu.mario.engine.BgRenderer;
import dk.itu.mario.engine.DataRecorder;
import dk.itu.mario.engine.LevelRenderer;
import dk.itu.mario.engine.MarioComponent;
import dk.itu.mario.engine.sonar.FixedSoundSource;
import dk.itu.mario.engine.sprites.BulletBill;
import dk.itu.mario.engine.sprites.CoinAnim;
import dk.itu.mario.engine.sprites.FireFlower;
import dk.itu.mario.engine.sprites.Fireball;
import dk.itu.mario.engine.sprites.Mario;
import dk.itu.mario.engine.sprites.Mushroom;
import dk.itu.mario.engine.sprites.Particle;
import dk.itu.mario.engine.sprites.Shell;
import dk.itu.mario.engine.sprites.Sparkle;
import dk.itu.mario.engine.sprites.Sprite;
import dk.itu.mario.engine.sprites.SpriteContext;
import dk.itu.mario.engine.sprites.SpriteTemplate;
import dk.itu.mario.level.Level;
public class LevelScene extends Scene implements SpriteContext {
protected List<Sprite> sprites = new ArrayList<Sprite>();
protected List<Sprite> spritesToAdd = new ArrayList<Sprite>();
protected List<Sprite> spritesToRemove = new ArrayList<Sprite>();
public Level level;
public Mario mario;
public float xCam, yCam, xCamO, yCamO;
public static Image tmpImage;
protected int tick;
protected LevelRenderer layer;
protected BgRenderer[] bgLayer = new BgRenderer[2];
protected Level currentLevel;
protected GraphicsConfiguration graphicsConfiguration;
public boolean paused = false;
public int startTime = 0;
public int timeLeft;
protected long levelSeed;
protected MarioComponent marioComponent;
//protected int levelType;
//protected int levelDifficulty;
public static DataRecorder recorder;
public boolean gameStarted;
public static boolean bothPlayed = false;
private int[] xPositionsArrow;
private int[] yPositionsArrow;
private int widthArrow, heightArrow, tipWidthArrow;
private int xArrow, yArrow;
public LevelScene(GraphicsConfiguration graphicsConfiguration,
MarioComponent renderer, long seed/*, int levelDifficulty, int type*/) {
this.graphicsConfiguration = graphicsConfiguration;
this.levelSeed = seed;
this.marioComponent = renderer;
//this.levelDifficulty = levelDifficulty;
//this.levelType = type;
widthArrow = 25;
tipWidthArrow = 10;
heightArrow = 20;
xArrow = 160;
yArrow = 40;
xPositionsArrow = new int[] { xArrow + -widthArrow / 2,
xArrow + widthArrow / 2 - tipWidthArrow,
xArrow + widthArrow / 2 - tipWidthArrow,
xArrow + widthArrow / 2,
xArrow + widthArrow / 2 - tipWidthArrow,
xArrow + widthArrow / 2 - tipWidthArrow,
xArrow + -widthArrow / 2 };
yPositionsArrow = new int[] { yArrow + -heightArrow / 4,
yArrow + -heightArrow / 4, yArrow + -heightArrow / 2,
yArrow + 0, yArrow + heightArrow / 2, yArrow + heightArrow / 4,
yArrow + heightArrow / 4 };
}
public void init() {
}
public int fireballsOnScreen = 0;
List<Shell> shellsToCheck = new ArrayList<Shell>();
public void checkShellCollide(Shell shell) {
shellsToCheck.add(shell);
}
List<Fireball> fireballsToCheck = new ArrayList<Fireball>();
public void checkFireballCollide(Fireball fireball) {
fireballsToCheck.add(fireball);
}
public void tick() {
timeLeft--;
if (widthArrow < 0) {
widthArrow *= -1;
tipWidthArrow *= -1;
xPositionsArrow = new int[] { xArrow + -widthArrow / 2,
xArrow + widthArrow / 2 - tipWidthArrow,
xArrow + widthArrow / 2 - tipWidthArrow,
xArrow + widthArrow / 2,
xArrow + widthArrow / 2 - tipWidthArrow,
xArrow + widthArrow / 2 - tipWidthArrow,
xArrow + -widthArrow / 2 };
yPositionsArrow = new int[] { yArrow + -heightArrow / 4,
yArrow + -heightArrow / 4, yArrow + -heightArrow / 2,
yArrow + 0, yArrow + heightArrow / 2,
yArrow + heightArrow / 4, yArrow + heightArrow / 4 };
}
if (timeLeft == 0) {
mario.dieTime();
}
xCamO = xCam;
yCamO = yCam;
if (startTime > 0) {
startTime++;
}
float targetXCam = mario.x - 160;
xCam = targetXCam;
if (xCam < 0)
xCam = 0;
if (xCam > level.getWidth() * 16 - 320)
xCam = level.getWidth() * 16 - 320;
/*
* if (recorder != null) { recorder.addTick(mario.getKeyMask()); }
*
* if (replayer!=null) { mario.setKeys(replayer.nextTick()); }
*/
fireballsOnScreen = 0;
for (Sprite sprite : sprites) {
if (sprite != mario) {
float xd = sprite.x - xCam;
float yd = sprite.y - yCam;
if (xd < -64 || xd > 320 + 64 || yd < -64 || yd > 240 + 64) {
removeSprite(sprite);
} else {
if (sprite instanceof Fireball) {
fireballsOnScreen++;
}
}
}
}
if (paused) {
for (Sprite sprite : sprites) {
if (sprite == mario) {
sprite.tick();
} else {
sprite.tickNoMove();
}
}
} else {
tick++;
level.tick();
boolean hasShotCannon = false;
int xCannon = 0;
for (int x = (int) xCam / 16 - 1; x <= (int) (xCam + layer.width) / 16 + 1; x++)
for (int y = (int) yCam / 16 - 1; y <= (int) (yCam + layer.height) / 16 + 1; y++) {
int dir = 0;
if (x * 16 + 8 > mario.x + 16)
dir = -1;
if (x * 16 + 8 < mario.x - 16)
dir = 1;
SpriteTemplate st = level.getSpriteTemplate(x, y);
if (st != null) {
if (st.lastVisibleTick != tick - 1) {
if (st.sprite == null
|| !sprites.contains(st.sprite)) {
st.spawn(this, x, y, dir);
}
}
st.lastVisibleTick = tick;
}
if (dir != 0) {
byte b = level.getBlock(x, y);
if (((Level.TILE_BEHAVIORS[b & 0xff]) & Level.BIT_ANIMATED) > 0) {
if ((b % 16) / 4 == 3 && b / 16 == 0) {
if ((tick - x * 2) % 100 == 0) {
xCannon = x;
for (int i = 0; i < 8; i++) {
addSprite(new Sparkle(x * 16 + 8, y
* 16
+ (int) (Math.random() * 16),
(float) Math.random() * dir, 0,
0, 1, 5));
}
addSprite(new BulletBill(this, x * 16 + 8
+ dir * 8, y * 16 + 15, dir));
hasShotCannon = true;
}
}
}
}
}
if (hasShotCannon) {
sound.play(Art.samples[Art.SAMPLE_CANNON_FIRE],
new FixedSoundSource(xCannon * 16, yCam + 120), 1, 1, 1);
}
for (Sprite sprite : sprites) {
sprite.tick();
}
for (Sprite sprite : sprites) {
sprite.collideCheck();
}
for (Shell shell : shellsToCheck) {
for (Sprite sprite : sprites) {
if (sprite != shell && !shell.dead) {
if (sprite.shellCollideCheck(shell)) {
if (mario.carried == shell && !shell.dead) {
mario.carried = null;
shell.die();
}
}
}
}
}
shellsToCheck.clear();
for (Fireball fireball : fireballsToCheck) {
for (Sprite sprite : sprites) {
if (sprite != fireball && !fireball.dead) {
if (sprite.fireballCollideCheck(fireball)) {
fireball.die();
}
}
}
}
fireballsToCheck.clear();
}
sprites.addAll(0, spritesToAdd);
sprites.removeAll(spritesToRemove);
spritesToAdd.clear();
spritesToRemove.clear();
}
private DecimalFormat df = new DecimalFormat("00");
private DecimalFormat df2 = new DecimalFormat("000");
public void render(Graphics g, float alpha) {
int xCam = (int) (mario.xOld + (mario.x - mario.xOld) * alpha) - 160;
int yCam = (int) (mario.yOld + (mario.y - mario.yOld) * alpha) - 120;
if (xCam < 0)
xCam = 0;
if (yCam < 0)
yCam = 0;
if (xCam > level.getWidth() * 16 - 320)
xCam = level.getWidth() * 16 - 320;
if (yCam > level.getHeight() * 16 - 240)
yCam = level.getHeight() * 16 - 240;
// g.drawImage(Art.background, 0, 0, null);
for (int i = 0; i < 2; i++) {
bgLayer[i].setCam(xCam, yCam);
bgLayer[i].render(g, tick, alpha);
}
g.translate(-xCam, -yCam);
for (Sprite sprite : sprites) {
if (sprite.layer == 0)
sprite.render(g, alpha);
}
g.translate(xCam, yCam);
// //////////THIS RENDERS THE LEVEL
layer.setCam(xCam, yCam);
layer.render(g, tick, paused ? 0 : alpha);
layer.renderExit0(g, tick, paused ? 0 : alpha, mario.winTime == 0);
// //////////END OF LEVEL RENDER
// //////////RENDERS SPRITES
g.translate(-xCam, -yCam);
for (Sprite sprite : sprites) {
if (sprite.layer == 1)
sprite.render(g, alpha);
}
g.translate(xCam, yCam);
g.setColor(Color.BLACK);
layer.renderExit1(g, tick, paused ? 0 : alpha);
// //////////END OF SPRITE RENDERING
drawStringDropShadow(g, "MARIO " + df.format(Mario.lives), 0, 0, 7);
// drawStringDropShadow(g, "00000000", 0, 1, 7);
drawStringDropShadow(g, "COIN", 14, 0, 7);
drawStringDropShadow(g, " " + df.format(Mario.coins), 14, 1, 7);
drawStringDropShadow(g, "WORLD", 24, 0, 7);
drawStringDropShadow(g, " " + Mario.levelString, 24, 1, 7);
drawStringDropShadow(g, "TIME", 35, 0, 7);
int time = (timeLeft + 15 - 1) / 15;
if (time < 0)
time = 0;
drawStringDropShadow(g, " " + df2.format(time), 35, 1, 7);
renderDirectionArrow(g);
if (startTime > 0) {
float t = startTime + alpha - 2;
t = t * t * 0.6f;
renderBlackout(g, 160, 120, (int) (t));
}
// mario.x>level.xExit*16
if (mario.winTime > 0) {
float t = mario.winTime + alpha;
t = t * t * 0.2f;
if (t > 0) {
if (recorder != null) {
recorder.stopRecord();
recorder.levelWon();
// recorder.printAll();
}
}
if (t > 900) {
winActions();
return;
// replayer = new Replayer(recorder.getBytes());
// init();
}
renderBlackout(g, (int) (mario.xDeathPos - xCam),
(int) (mario.yDeathPos - yCam), (int) (320 - t));
}
if (mario.deathTime > 0) {
g.setColor(Color.BLACK);
float t = mario.deathTime + alpha;
t = t * t * 0.4f;
if (t > 0 && Mario.lives <= 0) {
if (recorder != null) {
recorder.stopRecord();
}
}
if (t > 1800) {
Mario.lives--;
deathActions();
}
renderBlackout(g, (int) (mario.xDeathPos - xCam),
(int) (mario.yDeathPos - yCam), (int) (320 - t));
}
}
public void winActions() {
}
public void deathActions() {
}
protected void reset() {
paused = false;
Sprite.spriteContext = this;
sprites.clear();
try {
level = currentLevel.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
level.resetSpriteTemplate();
layer = new LevelRenderer(level, graphicsConfiguration, 320, 240);
mario = new Mario(this);
sprites.add(mario);
startTime = 1;
timeLeft = 200 * 15;
Art.startMusic(1);
tick = 0;
if (recorder != null) {
recorder.detailedLog = "";
}
gameStarted = false;
}
private void renderDirectionArrow(Graphics g) {
if (widthArrow < 0)
g.setColor(new Color(0, 0, 255, 150));
else
g.setColor(new Color(255, 0, 0, 150));
g.fillPolygon(xPositionsArrow, yPositionsArrow,
Math.min(xPositionsArrow.length, yPositionsArrow.length));
g.setColor(new Color(0, 0, 0, 255));
g.drawPolygon(xPositionsArrow, yPositionsArrow,
Math.min(xPositionsArrow.length, yPositionsArrow.length));
}
private void drawStringDropShadow(Graphics g, String text, int x, int y,
int c) {
drawString(g, text, x * 8 + 5, y * 8 + 5, 0);
drawString(g, text, x * 8 + 4, y * 8 + 4, c);
}
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);
}
}
float decrease = (float) 0.03;
float factor = 0;
boolean in = true;
String flipText = "FLIP! MOVE THE OTHER WAY!";
private void renderBlackout(Graphics g, int x, int y, int radius) {
if (radius > 320)
return;
int[] xp = new int[20];
int[] yp = new int[20];
for (int i = 0; i < 16; i++) {
xp[i] = x + (int) (Math.cos(i * Math.PI / 15) * radius);
yp[i] = y + (int) (Math.sin(i * Math.PI / 15) * radius);
}
xp[16] = 320;
yp[16] = y;
xp[17] = 320;
yp[17] = 240;
xp[18] = 0;
yp[18] = 240;
xp[19] = 0;
yp[19] = y;
g.fillPolygon(xp, yp, xp.length);
for (int i = 0; i < 16; i++) {
xp[i] = x - (int) (Math.cos(i * Math.PI / 15) * radius);
yp[i] = y - (int) (Math.sin(i * Math.PI / 15) * radius);
}
xp[16] = 320;
yp[16] = y;
xp[17] = 320;
yp[17] = 0;
xp[18] = 0;
yp[18] = 0;
xp[19] = 0;
yp[19] = y;
g.fillPolygon(xp, yp, xp.length);
}
public void addSprite(Sprite sprite) {
spritesToAdd.add(sprite);
sprite.tick();
}
public void removeSprite(Sprite sprite) {
spritesToRemove.add(sprite);
}
public float getX(float alpha) {
int xCam = (int) (mario.xOld + (mario.x - mario.xOld) * alpha) - 160;
if (xCam < 0)
xCam = 0;
return xCam + 160;
}
public float getY(float alpha) {
return 0;
}
public void bump(int x, int y, boolean canBreakBricks) {
byte block = level.getBlock(x, y);
if ((Level.TILE_BEHAVIORS[block & 0xff] & Level.BIT_BUMPABLE) > 0) {
bumpInto(x, y - 1);
level.setBlock(x, y, (byte) 4);
if (((Level.TILE_BEHAVIORS[block & 0xff]) & Level.BIT_SPECIAL) > 0) {
sound.play(Art.samples[Art.SAMPLE_ITEM_SPROUT],
new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1);
if (!Mario.large) {
addSprite(new Mushroom(this, x * 16 + 8, y * 16 + 8));
} else {
addSprite(new FireFlower(this, x * 16 + 8, y * 16 + 8));
}
if (recorder != null) {
recorder.blockPowerDestroyRecord();
}
} else {
if (recorder != null) {
recorder.blockCoinDestroyRecord();
}
Mario.getCoin();
sound.play(Art.samples[Art.SAMPLE_GET_COIN],
new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1);
addSprite(new CoinAnim(x, y));
}
}
if ((Level.TILE_BEHAVIORS[block & 0xff] & Level.BIT_BREAKABLE) > 0) {
bumpInto(x, y - 1);
if (canBreakBricks) {
if (recorder != null) {
recorder.blockEmptyDestroyRecord();
}
sound.play(Art.samples[Art.SAMPLE_BREAK_BLOCK],
new FixedSoundSource(x * 16 + 8, y * 16 + 8), 1, 1, 1);
level.setBlock(x, y, (byte) 0);
for (int xx = 0; xx < 2; xx++)
for (int yy = 0; yy < 2; yy++)
addSprite(new Particle(x * 16 + xx * 8 + 4, y * 16 + yy
* 8 + 4, (xx * 2 - 1) * 4, (yy * 2 - 1) * 4 - 8));
}
}
}
public void bumpInto(int x, int y) {
byte block = level.getBlock(x, y);
if (((Level.TILE_BEHAVIORS[block & 0xff]) & Level.BIT_PICKUPABLE) > 0) {
Mario.getCoin();
sound.play(Art.samples[Art.SAMPLE_GET_COIN], new FixedSoundSource(
x * 16 + 8, y * 16 + 8), 1, 1, 1);
level.setBlock(x, y, (byte) 0);
addSprite(new CoinAnim(x, y + 1));
// TODO no idea when this happens... maybe remove coin count
if (recorder != null)
recorder.recordCoin();
}
for (Sprite sprite : sprites) {
sprite.bumpCheck(x, y);
}
}
public void setLevel(Level level) {
this.level = level;
}
@Override
public void mouseClicked(MouseEvent me) {
}
}