package com.alarmclocksnoozers.runnershigh;
import java.util.Random;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.Log;
public class Level {
private int width;
private int height;
private float levelPosition;
private float deltaLevelPosition;
//public static float scoreCounter;
public float baseSpeed;
public float baseSpeedStart;
public float baseSpeedMax;
public float baseSpeedMaxStart;
public float baseSpeedAcceleration;
public float extraSpeed;
public float extraSpeedStart;
public float extraSpeedMax;
public float extraSpeedMaxStart;
public float extraSpeedAcceleration;
public int timeUntilNextSpeedIncreaseMillis;
public static Block[] blockData;
public static final int maxBlocks = 5;
private int leftBlockIndex;
private int rightBlockIndex;
public static Obstacle[] obstacleDataSlower;
public static final int maxObstaclesSlower = maxBlocks;
private int leftSlowerIndex;
private int rightSlowerIndex;
public static ObstacleJump[] obstacleDataJumper;
public static final int maxObstaclesJumper = maxBlocks;
private int leftJumperIndex;
private int rightJumperIndex;
public static ObstacleBonus[] obstacleDataBonus;
public static final int maxObstaclesBonus = maxBlocks;
private int leftBonusIndex;
private int rightBonusIndex;
private float obstacleJumperWidth;
private float obstacleJumperHeight;
private float obstacleSlowerWidth;
private float obstacleSlowerHeight;
private float obstacleBonusWidth;
private float obstacleBonusHeight;
private float obstacleBonusDistanceToBlock;
private final int OBSTACLEMASK_0_NO_OBSTACLE = 80;
private final int OBSTACLEMASK_1_JUMP = 30;
private final int OBSTACLEMASK_2_SLOW = 30;
private final int OBSTACLEMASK_3_JUMP_SLOW = 20;
private final int OBSTACLEMASK_4_BONUS = 40;
private final int OBSTACLEMASK_5_JUMP_BONUS = 20;
private final int OBSTACLEMASK_6_SLOW_BONUS = 20;
private final int OBSTACLEMASK_7_JUMP_SLOW_BONUS = 10;
private final int OBSTACLEMASK_MAX =
OBSTACLEMASK_0_NO_OBSTACLE +
OBSTACLEMASK_1_JUMP +
OBSTACLEMASK_2_SLOW +
OBSTACLEMASK_3_JUMP_SLOW +
OBSTACLEMASK_4_BONUS +
OBSTACLEMASK_5_JUMP_BONUS +
OBSTACLEMASK_6_SLOW_BONUS +
OBSTACLEMASK_7_JUMP_SLOW_BONUS;
private Bitmap obstacleSlowImg = null;
private Bitmap obstacleBonusImg = null;
private boolean slowDown;
Rect blockRect;
private int BlockCounter;
private OpenGLRenderer renderer;
private Random randomGenerator;
private boolean lastBlockWasSmall = false;
private int minBlockWidth = 0;
private RHDrawable mWaves = null;
public Level(Context context, OpenGLRenderer glrenderer, int _width, int _heigth) {
if(Settings.RHDEBUG)
Log.d("debug", "in Level constructor");
width = _width;
height = _heigth;
levelPosition = 0;
//lastLevelPosition = 0;
deltaLevelPosition = 0;
//scoreCounter = 0;
baseSpeedStart = Util.getPercentOfScreenWidth(0.095f);
baseSpeed = baseSpeedStart;
baseSpeedMaxStart = Util.getPercentOfScreenWidth(0.2f);
baseSpeedMax = baseSpeedMaxStart;
baseSpeedAcceleration = baseSpeed*0.025f;
extraSpeedStart = Util.getPercentOfScreenWidth(0.025f);
extraSpeed = extraSpeedStart;
extraSpeedMaxStart = Util.getPercentOfScreenWidth(0.5f);
extraSpeedMax = extraSpeedMaxStart;
extraSpeedAcceleration = extraSpeed * 0.005f;
timeUntilNextSpeedIncreaseMillis = Settings.TimeOfFirstSpeedIncrease;
obstacleJumperWidth = Util.getPercentOfScreenWidth(4.875f);
obstacleJumperHeight = Util.getPercentOfScreenHeight(14.25f);
obstacleSlowerWidth = Util.getPercentOfScreenWidth(6);
obstacleSlowerHeight= Util.getPercentOfScreenHeight(6);
obstacleBonusWidth = Util.getPercentOfScreenWidth(5);
obstacleBonusHeight = obstacleBonusWidth*Util.mWidthHeightRatio;
obstacleBonusDistanceToBlock = Util.getPercentOfScreenHeight(12);
if(Settings.RHDEBUG){
Log.d("debug", "obstacleJumperWidth" + obstacleJumperWidth);
Log.d("debug", "obstacleJumperHeight" + obstacleJumperHeight);
Log.d("debug", "obstacleSlowerWidth" + obstacleSlowerWidth);
Log.d("debug", "obstacleSlowerHeight" + obstacleSlowerHeight);
Log.d("debug", "obstacleBonusWidth" + obstacleBonusWidth);
Log.d("debug", "obstacleBonusHeight" + obstacleBonusHeight);
Log.d("debug", "obstacleBonusDistanceToBlock" + obstacleBonusDistanceToBlock);
}
renderer = glrenderer;
randomGenerator = new Random();
blockData = new Block[maxBlocks];
leftBlockIndex = 0;
rightBlockIndex = maxBlocks;
obstacleDataSlower = new Obstacle[maxObstaclesSlower];
leftSlowerIndex = 0;
rightSlowerIndex = maxObstaclesSlower;
obstacleDataJumper = new ObstacleJump[maxObstaclesJumper];
leftJumperIndex = 0;
rightJumperIndex = maxObstaclesJumper;
obstacleDataBonus = new ObstacleBonus[maxObstaclesBonus];
leftBonusIndex = 0;
rightBonusIndex = maxObstaclesBonus;
obstacleSlowImg = Util.loadBitmapFromAssets("game_obstacle_slow.png");
obstacleBonusImg =Util.loadBitmapFromAssets("game_obstacle_bonus.png");
Block.setTextureLeft(Util.loadBitmapFromAssets("game_block_left.png"));
Block.setTextureMiddle(Util.loadBitmapFromAssets("game_block_middle.png"));
Block.setTextureRight(Util.loadBitmapFromAssets("game_block_right.png"));
slowDown = false;
initializeBlocks(true);
initializeObstacles(true);
mWaves = new RHDrawable(0, 0, 0.7f, width*4, height);
mWaves.loadBitmap(Util.loadBitmapFromAssets("game_waves.png")
, GL10.GL_REPEAT, GL10.GL_CLAMP_TO_EDGE);
renderer.addMesh(mWaves);
}
public void cleanup() {
if (obstacleSlowImg != null) obstacleSlowImg.recycle();
//if (obstacleJumpImg != null) obstacleJumpImg.recycle();
if (obstacleBonusImg != null) obstacleBonusImg.recycle();
//TODO clean bonus effect in obstacleBonus
//TODO clean jumper sprite in obstaclejump
Block.cleanup();
}
public void update() {
synchronized (blockData) {
//Log.d("debug", "in update");
if (0 > blockData[leftBlockIndex].BlockRect.right) {
appendBlockToEnd(-1);
if(BlockCounter == 5)
appendObstaclesToEnd(false, false, true);
if(BlockCounter == 7)
appendObstaclesToEnd(true, false, false);
if(BlockCounter == 9)
appendObstaclesToEnd(false, true, false);
if (BlockCounter > 15)
decideIfAndWhatObstaclesSpawn();
}
baseSpeedAcceleration = baseSpeed * 0.005f;
extraSpeedAcceleration = extraSpeed * 0.002f;
//Log.d("debug", "getTimeSinceRoundStartMillis: " + Util.getTimeSinceRoundStartMillis());
if(Util.getTimeSinceRoundStartMillis() > timeUntilNextSpeedIncreaseMillis){
timeUntilNextSpeedIncreaseMillis += Settings.timeToFurtherSpeedIncreaseMillis;
baseSpeedMax += Util.getPercentOfScreenWidth(0.075f);
}
if(baseSpeed < baseSpeedMax)
baseSpeed+=baseSpeedAcceleration;
if(extraSpeed < extraSpeedMax)
extraSpeed+=extraSpeedAcceleration;
if(slowDown){
baseSpeed=baseSpeedStart;
extraSpeed /= 2;
slowDown=false;
}
deltaLevelPosition = baseSpeed + extraSpeed;
levelPosition += deltaLevelPosition;
mWaves.x -= deltaLevelPosition+2;
if (mWaves.x < -mWaves.width/2)
mWaves.x = 0;
//Log.d("debug", "deltaLevelPosition/10: " + deltaLevelPosition/10);
//scoreCounter += deltaLevelPosition/10;
for (int i = 0; i < maxBlocks; i++)
{
blockData[i].x -= deltaLevelPosition;
blockData[i].updateRect();
}
for (int i = 0; i < maxObstaclesJumper; i++)
{
obstacleDataJumper[i].x -= deltaLevelPosition;
obstacleDataJumper[i].jumpSprite.x -= deltaLevelPosition;
obstacleDataJumper[i].jumpSprite.tryToSetNextFrame();
}
for (int i = 0; i < maxObstaclesSlower; i++)
{
obstacleDataSlower[i].x -= deltaLevelPosition;
}
for (int i = 0; i < maxObstaclesBonus; i++)
{
obstacleDataBonus[i].centerX -= deltaLevelPosition;
obstacleDataBonus[i].updateObstacleCircleMovement();
obstacleDataBonus[i].bonusScoreEffect.updateBonusScoreEffect(deltaLevelPosition);
}
//lastLevelPosition=levelPosition;
//Log.d("debug", "in update after value mod");
}
}
private void initializeBlocks(Boolean firstTime) {
if(Settings.RHDEBUG)
Log.d("debug", "in initializeBlocks");
//Log.d("debug", "blockData.size() -> " + Integer.toString(blockData.size()) );
if (firstTime)
blockData[0] = new Block();
blockData[0].x = 0;
blockData[0].setWidth(width);
blockData[0].setHeight(Settings.FirstBlockHeight);
blockData[0].updateRect();
if(Settings.RHDEBUG)
Log.d("debug", "after blockdata 0");
if(firstTime)
renderer.addMesh(blockData[0]);
leftBlockIndex = 1;
rightBlockIndex = 0;
if(Settings.RHDEBUG)
Log.d("debug", "before for");
for(int i = 1; i < maxBlocks; i++)
{
if (firstTime){
blockData[i] = new Block();
renderer.addMesh(blockData[i]);
}
appendBlockToEnd(i);
blockData[i].updateRect();
}
if(Settings.RHDEBUG)
Log.d("debug", "left initializeBlocks");
}
private void appendBlockToEnd(int BlockNumber)
{
if (minBlockWidth == 0) {
minBlockWidth =
Block.getTextureLeftWidth() +
Block.getTextureRightWidth() +
Block.getTextureMiddleWidth() * 2;
}
//Log.d("debug", "in appendBlockToEnd");
float newHeight=0;
float oldHeight;
float newWidth=0;
float distance;
float newLeft;
boolean thisBlockIsSmall = false;
oldHeight = blockData[rightBlockIndex].BlockRect.top;
if(BlockNumber==-1){
if (oldHeight > height/2)
newHeight = (int)(Math.random()*height/3*2 + height/8);
else
newHeight = (int)(Math.random()*height/4 + height/8);
if(Util.getTimeSinceRoundStartMillis() > Settings.timeUntilLongBlocksStopMillis){
//Log.d("debug", "in normal block generation ");
if (lastBlockWasSmall) lastBlockWasSmall = false;
else if (50 - BlockCounter <= 0) thisBlockIsSmall = true;
else thisBlockIsSmall = (randomGenerator.nextInt(50 - BlockCounter) <= 5);
if (thisBlockIsSmall) {
newWidth = minBlockWidth;
lastBlockWasSmall = true;
}
else {
newWidth = (int)(Math.random()*width/3+width/3);
}
}else{
newWidth = (int)(Math.random()*width/3+width*0.70f);
}
newWidth -= (newWidth - Block.getTextureLeftWidth() - Block.getTextureRightWidth()) % (Block.getTextureMiddleWidth());
distance = (int)(Math.random()*width/16+width/12);
if(distance <= Player.width)
distance = Player.width+10;
}else{
distance = Player.width+5;
switch (BlockNumber){
case 1:
newHeight=oldHeight;
newWidth=Util.getPercentOfScreenWidth(80);
break;
case 2:
newHeight=oldHeight+Util.getPercentOfScreenHeight(8);
newWidth=Util.getPercentOfScreenWidth(80);
break;
case 3:
newHeight=oldHeight;
newWidth=Util.getPercentOfScreenWidth(80);
break;
case 4:
newHeight=oldHeight+Util.getPercentOfScreenHeight(9);
newWidth=Util.getPercentOfScreenWidth(80);
break;
}
}
// Block lastBlock = blockData[rightBlockIndex];
// newLeft = lastBlock.BlockRect.right + distance;
newLeft = blockData[rightBlockIndex].BlockRect.right + distance;
blockData[leftBlockIndex].setHeight(newHeight);
blockData[leftBlockIndex].setWidth(newWidth);
blockData[leftBlockIndex].x = newLeft;
leftBlockIndex++;
if (leftBlockIndex == maxBlocks)
leftBlockIndex = 0;
rightBlockIndex++;
if (rightBlockIndex== maxBlocks)
rightBlockIndex = 0;
BlockCounter++;
//Log.d("debug", "left appendBlockToEnd");
}
private void initializeObstacles(Boolean firstTime)
{
for(int i = 0; i < maxObstaclesJumper; i++)
{
if (firstTime)
{
obstacleDataJumper[i] = new ObstacleJump(-1000, 0, 0.9f, obstacleJumperWidth, obstacleJumperHeight, 'j', 60, 4);
}
obstacleDataJumper[i].x = obstacleDataJumper[i].jumpSprite.x = -1000;
obstacleDataJumper[i].didTrigger = false;
}
for(int i = 0; i < maxObstaclesSlower; i++)
{
if (firstTime)
{
obstacleDataSlower[i] = new Obstacle(-1000, 0, 0.9f, obstacleSlowerWidth, obstacleSlowerHeight, 's');
renderer.addMesh(obstacleDataSlower[i]);
obstacleDataSlower[i].loadBitmap(obstacleSlowImg);
}
obstacleDataSlower[i].x = -1000;
obstacleDataSlower[i].didTrigger = false;
}
for(int i = 0; i < maxObstaclesBonus; i++)
{
if (firstTime)
{
obstacleDataBonus[i] = new ObstacleBonus(-1000, 0, 0.9f, obstacleBonusWidth, obstacleBonusHeight, 'b');
renderer.addMesh(obstacleDataBonus[i]);
obstacleDataBonus[i].loadBitmap(obstacleBonusImg);
}
obstacleDataBonus[i].centerX = -1000;
obstacleDataBonus[i].bonusScoreEffect.effectX=-1000;
obstacleDataBonus[i].didTrigger = false;
}
}
private void decideIfAndWhatObstaclesSpawn()
{
int obstacleValue =randomGenerator.nextInt(OBSTACLEMASK_MAX);
if (obstacleValue < OBSTACLEMASK_0_NO_OBSTACLE)
{
return;
}
obstacleValue -= OBSTACLEMASK_0_NO_OBSTACLE;
if (obstacleValue < OBSTACLEMASK_1_JUMP)
{
appendObstaclesToEnd(true, false, false);
return;
}
obstacleValue -= OBSTACLEMASK_1_JUMP;
if (obstacleValue < OBSTACLEMASK_2_SLOW)
{
appendObstaclesToEnd(false, true, false);
return;
}
obstacleValue -= OBSTACLEMASK_2_SLOW;
if (obstacleValue < OBSTACLEMASK_3_JUMP_SLOW)
{
appendObstaclesToEnd(true, true, false);
return;
}
obstacleValue -= OBSTACLEMASK_3_JUMP_SLOW;
if (obstacleValue < OBSTACLEMASK_4_BONUS)
{
appendObstaclesToEnd(false, false, true);
return;
}
obstacleValue -= OBSTACLEMASK_4_BONUS;
if (obstacleValue < OBSTACLEMASK_5_JUMP_BONUS)
{
appendObstaclesToEnd(true, false, true);
return;
}
obstacleValue -= OBSTACLEMASK_5_JUMP_BONUS;
if (obstacleValue < OBSTACLEMASK_6_SLOW_BONUS)
{
appendObstaclesToEnd(false, true, true);
return;
}
obstacleValue -= OBSTACLEMASK_6_SLOW_BONUS;
if (obstacleValue < OBSTACLEMASK_7_JUMP_SLOW_BONUS)
{
appendObstaclesToEnd(true, true, true);
return;
}
obstacleValue -= OBSTACLEMASK_7_JUMP_SLOW_BONUS;
}
private void appendObstaclesToEnd(Boolean spawnJumper, Boolean spawnSlower, Boolean spawnBonus)
{
if (spawnSlower)
{
float obstacleLeft;
// compute a fraction of the range, 0 <= frac < range
long fraction = (long)(blockData[rightBlockIndex].mWidth * 0.33 * randomGenerator.nextDouble());
Obstacle newSlowObstacle = obstacleDataSlower[leftSlowerIndex];
newSlowObstacle.didTrigger = false;
obstacleLeft =
blockData[rightBlockIndex].x + blockData[rightBlockIndex].mWidth
- newSlowObstacle.width - fraction;
newSlowObstacle.x = obstacleLeft;
newSlowObstacle.y = blockData[rightBlockIndex].mHeight;
newSlowObstacle.setObstacleRect(
obstacleLeft,
obstacleLeft+newSlowObstacle.width,
blockData[rightBlockIndex].mHeight,
blockData[rightBlockIndex].mHeight-newSlowObstacle.height);
leftSlowerIndex++;
if (leftSlowerIndex == maxObstaclesSlower)
leftSlowerIndex = 0;
rightSlowerIndex++;
if (rightSlowerIndex == maxObstaclesSlower)
rightSlowerIndex = 0;
}
if (spawnJumper)
{
if(Settings.RHDEBUG)
Log.d("debug", "in spawnJumper");
float obstacleLeft;
ObstacleJump newJumpObstacle = obstacleDataJumper[leftJumperIndex];
newJumpObstacle.didTrigger = false;
long fraction = (long)(blockData[rightBlockIndex].mWidth * 0.33 * randomGenerator.nextDouble());
obstacleLeft = (blockData[rightBlockIndex].x + newJumpObstacle.width + fraction);
newJumpObstacle.x = obstacleLeft;
newJumpObstacle.jumpSprite.x = obstacleLeft;
newJumpObstacle.y = blockData[rightBlockIndex].mHeight;
newJumpObstacle.jumpSprite.y = blockData[rightBlockIndex].mHeight;
newJumpObstacle.setObstacleRect(
obstacleLeft,
obstacleLeft+newJumpObstacle.width,
blockData[rightBlockIndex].mHeight,
blockData[rightBlockIndex].mHeight-newJumpObstacle.height);
if(Settings.RHDEBUG)
Log.d("debug", "x: " + newJumpObstacle.x +
" / y: " + newJumpObstacle.y +
" / z: " + newJumpObstacle.z);
leftJumperIndex++;
if (leftJumperIndex == maxObstaclesJumper)
leftJumperIndex = 0;
rightJumperIndex++;
if (rightJumperIndex == maxObstaclesJumper)
rightJumperIndex = 0;
}
if (spawnBonus)
{
if(Settings.RHDEBUG)
Log.d("debug", "in spawnBonus");
float range = blockData[rightBlockIndex].mWidth;
int bonusLeft;
// compute a fraction of the range, 0 <= frac < range
double fraction = range * randomGenerator.nextDouble();
ObstacleBonus newBonus = obstacleDataBonus[leftBonusIndex];
newBonus.didTrigger = false;
newBonus.z=0;
bonusLeft = (int)(blockData[rightBlockIndex].x + fraction );
//set new coordinates
newBonus.x = newBonus.centerX = bonusLeft;
newBonus.y = newBonus.centerY = blockData[rightBlockIndex].mHeight+obstacleBonusDistanceToBlock+randomGenerator.nextInt(75);
newBonus.setObstacleRect(bonusLeft,
bonusLeft+newBonus.width,
blockData[rightBlockIndex].mHeight,
blockData[rightBlockIndex].mHeight-newBonus.height);
if(Settings.RHDEBUG)
Log.d("debug", "x: " + newBonus.x +
" / y: " + newBonus.y +
" / z: " + newBonus.z);
leftBonusIndex++;
if (leftBonusIndex == maxObstaclesBonus)
leftBonusIndex = 0;
rightBonusIndex++;
if (rightBonusIndex== maxObstaclesBonus)
rightBonusIndex = 0;
}
}
public int getDistanceScore()
{
return (int)(levelPosition * 800 / width / 10);
}
public void lowerSpeed() {
slowDown = true;
}
public float getLevelPosition(){
return levelPosition;
}
public void reset() {
synchronized (blockData) {
levelPosition = 0;
initializeBlocks(false);
initializeObstacles(false);
timeUntilNextSpeedIncreaseMillis = Settings.TimeOfFirstSpeedIncrease;
baseSpeed = baseSpeedStart;
extraSpeed = extraSpeedStart;
baseSpeedMax = baseSpeedMaxStart;
extraSpeedMax = extraSpeedMaxStart;
BlockCounter=0;
}
}
}