package com.gebauz.PonPonChun.gamestates;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.gebauz.Bauzoid.game.Game;
import com.gebauz.Bauzoid.gamestates.BaseGameState;
import com.gebauz.Bauzoid.graphics.sprite.AtlasSprite;
import com.gebauz.Bauzoid.graphics.sprite.AtlasSpriteInstance;
import com.gebauz.Bauzoid.graphics.sprite.Sprite;
import com.gebauz.Bauzoid.math.Interpolation;
import com.gebauz.Bauzoid.math.MathUtil;
import com.gebauz.PonPonChun.game.GameConsts;
import com.gebauz.PonPonChun.game.entities.Block;
import com.gebauz.PonPonChun.game.entities.BlockBreakParticles;
import com.gebauz.PonPonChun.game.entities.BlockSprites;
public class LogoState
extends BaseGameState
{
// Constants========================================================================================
public static final int NUM_BLOCKS =
6;
public static final int BLOCK_SIZE =
64;
public static final int BREAKBLOCK_SIZE =
68;
public static final int BLOCK_OFFSET =
4;
public static final float FALLING_SPEED = BLOCK_SIZE/0.05f
;
public static final float Y_TARGET = 400.0f
;
public static final float SQUASH_TIME = 0.2f
;
public static final float SWAP_TIME = 0.2f
;
public static final float CLEARING_TIME = 1.0f
;
public static final float LOGO_WAIT_TIME = 3.0f
;
public static final int BLOCK_TYPES
[] =
{
Block.
TYPE_BLUE, Block.
TYPE_BLUE, Block.
TYPE_RED,
Block.
TYPE_BLUE, Block.
TYPE_RED, Block.
TYPE_RED
};
// Embedded Types===================================================================================
public enum State
{
WAIT_FOR_BLOCKS,
SWAP_BLOCKS,
WAIT_FOR_BLOCKS_CLEARING,
WAIT_LOGO
}
public enum BlockState
{
FALLING,
SQUASHING,
RESTING,
CLEARING,
DESTROYED
}
public class LogoBlock
{
public int type
;
public float x
;
public float y
;
public float startY
;
public float timer
;
public BlockState state = BlockState.
FALLING;
public LogoBlock
(float _x,
float _y,
int _type
)
{
x = _x
;
y = _y
;
startY = _y
;
type = _type
;
timer =
0;
}
public void update
(float deltaTime
)
{
timer += deltaTime
;
if (state == BlockState.
FALLING)
{
if (y
< Y_TARGET
)
{
y += FALLING_SPEED
*deltaTime
;
if (y
>= Y_TARGET
)
{
y = Y_TARGET
;
mBlockFall.
play();
state = BlockState.
SQUASHING;
timer = 0.0f
;
}
}
}
else if (state == BlockState.
SQUASHING)
{
if (timer
> SQUASH_TIME
)
{
state = BlockState.
RESTING;
timer = 0.0f
;
}
}
else if (state == BlockState.
CLEARING)
{
if (timer
> CLEARING_TIME
)
{
mParticles.
spawnParticles(x, y-BLOCK_SIZE/
2);
mParticles.
spawnParticles(x, y+BLOCK_SIZE/
2);
state = BlockState.
DESTROYED;
timer = 0.0f
;
}
}
}
public void render
()
{
if (state == BlockState.
DESTROYED)
return;
AtlasSpriteInstance s = mBlockSprites.
getBlockSprite(type
);
float alphaMultiply =
1;
if (state == BlockState.
CLEARING)
{
alphaMultiply =
1 - MathUtil.
clamp(timer / CLEARING_TIME,
0,
1);
}
s.
x = x
;
s.
y = y
;
s.
w = BLOCK_SIZE
;
s.
h = BLOCK_SIZE
;
s.
pivotX = s.
w/
2;
s.
pivotY = s.
h;
s.
mirrorY =
false;
s.
alpha =
1*alphaMultiply
;
if (state == BlockState.
SQUASHING)
{
float f =
1 - MathUtil.
clamp(timer / SQUASH_TIME,
0,
1);
float squashFactor = f
*f
;
s.
w *= 1.2f - 0.2f
* squashFactor
;
s.
h *= 0.8f + 0.2f
* squashFactor
;
s.
pivotX = s.
w/
2;
s.
pivotY = s.
h;
}
s.
render();
float phase = getGame
().
getTime();
// render break sprite if applicable
renderBreakSprite
(s, phase
);
// render mirror image
s.
mirrorY =
true;
final float diffY = Y_TARGET
;
s.
y = Y_TARGET + diffY - y
;
s.
alpha = 0.5f
*alphaMultiply
;
s.
render();
renderBreakSprite
(s, phase
);
}
public void renderBreakSprite
(AtlasSpriteInstance s,
float phase
)
{
if (state == BlockState.
CLEARING)
{
AtlasSprite breakSprite = mBlockSprites.
getBreakSprite();
breakSprite.
x = s.
x;
breakSprite.
y = s.
y +
(BREAKBLOCK_SIZE-BLOCK_SIZE
)/
2;
breakSprite.
w = BREAKBLOCK_SIZE
;
breakSprite.
h = BREAKBLOCK_SIZE
;
breakSprite.
pivotX = breakSprite.
w/
2;
breakSprite.
pivotY = breakSprite.
h;
breakSprite.
mirrorY = s.
mirrorY;
if (breakSprite.
mirrorY)
breakSprite.
alpha = 0.5f
;
else
breakSprite.
alpha = 1.0f
;
float t = MathUtil.
clamp(timer / CLEARING_TIME,
0,
1);
//float t = CLEARING_TIME - timer;
if (t
< 0.2f
)
// fade in
breakSprite.
alpha *= t / 0.2f
;
else if (timer
<= 0.0f
)
breakSprite.
alpha *= 0.0f
;
else
breakSprite.
alpha *= 1.0f
;
float animate =
(phase
* 10.0f
) % 1.0f
;
int n =
0;
if (animate
< 0.33f
)
n =
1;
else if (animate
> 0.66f
)
n =
2;
breakSprite.
render(n
);
}
}
}
// Fields===========================================================================================
private BlockSprites mBlockSprites =
null;
private Sprite mBackground =
null;
private Sprite mGebauzLogo =
null;
private LogoBlock mBlocks
[] =
new LogoBlock
[NUM_BLOCKS
];
private BlockBreakParticles mParticles =
null;
private Sound mBlockFall =
null;
private Sound mBlockSwap =
null;
private Sound mBlockClear =
null;
private Sound mBlockClearDestroy =
null;
private State mState =
State.
WAIT_FOR_BLOCKS;
private float mStateTimer = 0.0f
;
// Methods==========================================================================================
public LogoState
(Game game
)
{
super(game
);
setFading
(true,
true);
mBlockSprites =
new BlockSprites
(getGraphics
());
mBackground =
new Sprite
(getGraphics
(),
"data/textures/logo_bg.png");
mParticles =
new BlockBreakParticles
(game, mBlockSprites
);
mGebauzLogo =
new Sprite
(getGraphics
(),
"data/textures/gebauzlogo.png");
}
@
Override
public void initAsync
(String param
)
{
mBackground.
initAsync();
mGebauzLogo.
initAsync();
getAssetManager
().
load("data/sounds/block_fall.wav", Sound.
class);
getAssetManager
().
load("data/sounds/swap.wav", Sound.
class);
getAssetManager
().
load("data/sounds/super_clear.wav", Sound.
class);
getAssetManager
().
load("data/sounds/glass_break.wav", Sound.
class);
}
@
Override
public void init
(String param
)
{
mBlockFall = getAssetManager
().
get("data/sounds/block_fall.wav", Sound.
class);
mBlockSwap = getAssetManager
().
get("data/sounds/swap.wav", Sound.
class);
mBlockClear = getAssetManager
().
get("data/sounds/super_clear.wav", Sound.
class);
mBlockClearDestroy = getAssetManager
().
get("data/sounds/glass_break.wav", Sound.
class);
mBlockSprites.
init();
mBackground.
init(0,
0, GameConsts.
VIRTUAL_SCREEN_WIDTH, GameConsts.
VIRTUAL_SCREEN_HEIGHT,
0,
0);
mGebauzLogo.
init(240,
350,
400,
100);
for (int i =
0; i
< NUM_BLOCKS
; i++
)
{
float posX = getBlockX
(i
);
float posY = -
20 - getGame
().
getRandomInt(0,
300);
mBlocks
[i
] =
new LogoBlock
(posX, posY, BLOCK_TYPES
[i
]);
}
mParticles.
init();
}
@
Override
public void exit
()
{
getAssetManager
().
unload("data/sounds/block_fall.wav");
getAssetManager
().
unload("data/sounds/swap.wav");
getAssetManager
().
unload("data/sounds/super_clear.wav");
getAssetManager
().
unload("data/sounds/glass_break.wav");
if (mParticles
!=
null)
{
mParticles.
exit();
mParticles =
null;
}
if (mBlockSprites
!=
null)
{
mBlockSprites.
exit();
mBlockSprites =
null;
}
if (mGebauzLogo
!=
null)
{
mGebauzLogo.
dispose();
mGebauzLogo =
null;
}
if (mBackground
!=
null)
{
mBackground.
dispose();
mBackground =
null;
}
}
@
Override
public void update
(float deltaTime
)
{
if (Gdx.
input.
justTouched())
{
getGameStateManager
().
switchTo(com.
gebauz.
PonPonChun.
gamestates.
TitleState.
class,
"");
}
for (int i =
0; i
< NUM_BLOCKS
; i++
)
{
mBlocks
[i
].
update(deltaTime
);
}
mStateTimer += deltaTime
;
switch(mState
)
{
case WAIT_FOR_BLOCKS:
updateWaitForBlocks
(deltaTime
);
break;
case SWAP_BLOCKS:
updateSwapBlocks
(deltaTime
);
break;
case WAIT_FOR_BLOCKS_CLEARING:
updateWaitForBlocksClearing
(deltaTime
);
break;
case WAIT_LOGO:
updateWaitLogo
(deltaTime
);
break;
}
mParticles.
update(deltaTime
);
}
public void updateWaitForBlocks
(float deltaTime
)
{
for (int i =
0; i
< NUM_BLOCKS
; i++
)
{
if (mBlocks
[i
].
state != BlockState.
RESTING)
{
return;
}
}
// only execute if all blocks are resting
mState =
State.
SWAP_BLOCKS;
mStateTimer =
0;
mBlockSwap.
play();
}
public void updateSwapBlocks
(float deltaTime
)
{
// swap block index 2 and 3
// block index 2 should move towards 3
float s = MathUtil.
clamp(mStateTimer / SWAP_TIME,
0,
1);
{
final float target = getBlockX
(3);
final float src = getBlockX
(2);
final float diff = target - src
;
mBlocks
[2].
x = src + diff
* s
;
}
// block index 3 should move towards 2
{
final float target = getBlockX
(2);
final float src = getBlockX
(3);
final float diff = target - src
;
mBlocks
[3].
x = src + diff
* s
;
}
if (mStateTimer
> SWAP_TIME
)
{
for (int i =
0; i
< NUM_BLOCKS
; i++
)
{
mBlocks
[i
].
state = BlockState.
CLEARING;
mBlocks
[i
].
timer =
0;
}
mState =
State.
WAIT_FOR_BLOCKS_CLEARING;
mStateTimer =
0;
mBlockClear.
play();
}
}
public void updateWaitForBlocksClearing
(float deltaTime
)
{
for (int i =
0; i
< NUM_BLOCKS
; i++
)
{
if (mBlocks
[i
].
state != BlockState.
DESTROYED)
return;
}
mBlockClearDestroy.
play();
mState =
State.
WAIT_LOGO;
mStateTimer = 0.0f
;
}
public void updateWaitLogo
(float deltaTime
)
{
if (mStateTimer
> LOGO_WAIT_TIME
)
{
// switch state
getGameStateManager
().
switchTo(com.
gebauz.
PonPonChun.
gamestates.
TitleState.
class,
"");
}
}
@
Override
public void render
()
{
getGraphics
().
clear(0,
0,
0,
0);
getRenderStates
().
projection.
setOrtho(
0.0f,
GameConsts.
VIRTUAL_SCREEN_WIDTH-
1,
GameConsts.
VIRTUAL_SCREEN_HEIGHT-
1,
0.0f,
0.0f,
1.0f
);
mBackground.
render();
if (/*(mState == State.WAIT_FOR_BLOCKS_CLEARING) ||*/
(mState ==
State.
WAIT_LOGO))
{
/*float a = mStateTimer / CLEARING_TIME;
if (a < 0.95f)
a = 0.0f;
else
a = MathUtil.clamp((a - 0.95f) / 0.05f, 0, 1);
a = 0.0f;
//if (mState == State.WAIT_LOGO)
a = 1.0f;*/
final float shiftY =
16;
mGebauzLogo.
x =
240;
mGebauzLogo.
y = Y_TARGET + shiftY
;
mGebauzLogo.
w =
400;
mGebauzLogo.
h =
100;
mGebauzLogo.
pivotX = mGebauzLogo.
w/
2;
mGebauzLogo.
pivotY = mGebauzLogo.
h;
mGebauzLogo.
mirrorY =
false;
mGebauzLogo.
alpha = 1.0f
;
mGebauzLogo.
render();
mGebauzLogo.
mirrorY =
true;
mGebauzLogo.
alpha = 0.3f
;
mGebauzLogo.
y = Y_TARGET - shiftY
;
mGebauzLogo.
render();
}
for (int i =
0; i
< NUM_BLOCKS
; i++
)
{
mBlocks
[i
].
render();
}
mParticles.
render();
}
public float getBlockX
(int i
)
{
final float totalWidth = NUM_BLOCKS
* BLOCK_SIZE +
(NUM_BLOCKS-
1) * BLOCK_OFFSET
;
return (GameConsts.
VIRTUAL_SCREEN_WIDTH - totalWidth
) /
2 + BLOCK_SIZE/
2 + i
* (BLOCK_SIZE+BLOCK_OFFSET
);
}
// Getters/Setters==================================================================================
}