package com.gebauz.pingK.game;
import java.util.Vector;
import com.gebauz.framework.util.MathUtil;
import com.gebauz.framework.util.Sprite2D;
import com.gebauz.framework.util.Vector2;
import com.gebauz.pingK.R;
public class Crystals
{
public class Particle
{
private float x
;
private float y
;
private float mAngle
;
private float mLifeTime
;
private int mNumSpawned
;
private Vector2 mDirection
;
private float mRegrowthTime
;
public Particle
(float posX,
float posY, Vector2 direction,
float regrowthTime
)
{
x = posX
;
y = posY
;
//mAngle = mGameLogic.getRandomFloat(0.0f, 360.0f);
mAngle =
new Vector2
(direction.
x, -direction.
y).
getAngle();
mLifeTime = 0.0f
;
mNumSpawned =
0;
mDirection = direction
;
mRegrowthTime = regrowthTime
;
}
public void update
(float deltaTime
)
{
mLifeTime += deltaTime
;
if ((mNumSpawned
< GameConsts.
POWERUP_CRYSTAL_PARTICLE_MAX_RESPAWN) && (mLifeTime
> mRegrowthTime
))
{
// check possible direction for growth (no other crystal must be in its way)
for (int i =
0; i
< 10; i++
)
{
//float nextX = x + mGameLogic.getRandomFloat(-d, d);
//float nextY = y + mGameLogic.getRandomFloat(-d, d);
float rot = mGameLogic.
getRandomFloat(0.0f, 360.0f
);
Vector2 direction = Vector2.
fromRotation(rot
);
float testX = x + direction.
x * GameConsts.
POWERUP_CRYSTAL_SIZE;
float testY = y + direction.
y * GameConsts.
POWERUP_CRYSTAL_SIZE;
float nextX = x + direction.
x * GameConsts.
POWERUP_CRYSTAL_PARTICLE_DISTANCE;
float nextY = y + direction.
y * GameConsts.
POWERUP_CRYSTAL_PARTICLE_DISTANCE;
if ((!mGameLogic.
isOutOfBoardInner(testX, testY
)) && (findCrystalAt
(testX, testY, GameConsts.
POWERUP_CRYSTAL_RADIUS - 5.0f
) ==
null))
{
// grow new
spawnCrystal
(nextX, nextY, direction
);
mNumSpawned++
;
break;
}
}
// reset grow timer
mLifeTime = GameConsts.
POWERUP_CRYSTAL_PARTICLE_FADE_TIME;
}
}
public void render
()
{
float growth = MathUtil.
clamp(mLifeTime / GameConsts.
POWERUP_CRYSTAL_PARTICLE_FADE_TIME, 0.0f, 1.0f
);
mCrystal.
x = x
;
mCrystal.
y = y
;
mCrystal.
w = GameConsts.
POWERUP_CRYSTAL_SIZE * growth
;
mCrystal.
h = GameConsts.
POWERUP_CRYSTAL_SIZE * growth
;
mCrystal.
pivotX = mCrystal.
w / 2.0f
;
mCrystal.
pivotY = mCrystal.
h / 2.0f
;
mCrystal.
angle = mAngle
;
mCrystal.
x -= mDirection.
x * GameConsts.
POWERUP_CRYSTAL_SIZE * (1.0f-growth
);
mCrystal.
y -= mDirection.
y * GameConsts.
POWERUP_CRYSTAL_SIZE * (1.0f-growth
);
mCrystal.
render();
}
public float distanceFrom
(float posX,
float posY
)
{
float dx = posX - x
;
float dy = posY - y
;
return ((float)Math.
sqrt(dx
*dx + dy
*dy
) - GameConsts.
POWERUP_CRYSTAL_RADIUS);
}
public boolean isInside
(float posX,
float posY
)
{
return (distanceFrom
(posX, posY
) <= 0.0f
);
/*float dx = posX - x;
float dy = posX - y;
float lengthSqr = dx*dx + dy*dy;
return (lengthSqr <= GameConsts.POWERUP_CRYSTAL_RADIUS_SQR);*/
}
/* public boolean isGrown()
{
return (mLifeTime > GameConsts.POWERUP_CRYSTAL_PARTICLE_GROWTH_TIME);
}*/
}
public class Shard
{
private float x
;
private float y
;
private int mSpriteIndex
;
private Vector2 mDirection
;
private float mLifeTime
;
private float mSize
;
public Shard
(float posX,
float posY,
int spriteIndex, Vector2 direction,
float size
)
{
x = posX
;
y = posY
;
mDirection = direction
;
mSpriteIndex = spriteIndex
;
mLifeTime = 0.0f
;
mSize = size
;
}
public void update
(float deltaTime
)
{
mLifeTime += deltaTime
;
x += mDirection.
x * deltaTime
;
y += mDirection.
y * deltaTime
;
}
public void render
()
{
float alpha = 1.0f - MathUtil.
clamp(mLifeTime/GameConsts.
POWERUP_CRYSTAL_SHARDS_LIFETIME, 0.0f, 1.0f
);
// TODO: ease?
mShardSprites
[mSpriteIndex
].
setColor(GameConsts.
PINGK_COLOR.
x, GameConsts.
PINGK_COLOR.
y, GameConsts.
PINGK_COLOR.
z, alpha
);
mShardSprites
[mSpriteIndex
].
x = x
;
mShardSprites
[mSpriteIndex
].
y = y
;
mShardSprites
[mSpriteIndex
].
w = 32.0f
;
mShardSprites
[mSpriteIndex
].
h = 32.0f
;
mShardSprites
[mSpriteIndex
].
angle = mLifeTime
* GameConsts.
POWERUP_CRYSTAL_SHARDS_ROTATE_SPEED;
mShardSprites
[mSpriteIndex
].
pivotX = mShardSprites
[mSpriteIndex
].
w/2.0f
;
mShardSprites
[mSpriteIndex
].
pivotY = mShardSprites
[mSpriteIndex
].
h/2.0f
;
mShardSprites
[mSpriteIndex
].
render();
}
public boolean isDone
()
{
return (mLifeTime
> GameConsts.
POWERUP_CRYSTAL_SHARDS_LIFETIME);
}
}
private GameLogic mGameLogic =
null;
private Vector<Particle
> mParticles =
new Vector<Particle
>();
private Vector<Shard
> mShards =
new Vector<Shard
>();
private static int[] mShardSpriteIds =
{
R.
drawable.
shard1,
R.
drawable.
shard2,
R.
drawable.
shard3,
R.
drawable.
shard4,
R.
drawable.
shard5,
};
private static final int NUM_SHARD_SPRITES = mShardSpriteIds.
length;
private Sprite2D mCrystal =
new Sprite2D
();
private Sprite2D
[] mShardSprites =
new Sprite2D
[NUM_SHARD_SPRITES
];
public Crystals
(GameLogic gameLogic
)
{
mGameLogic = gameLogic
;
mCrystal.
init(R.
drawable.
crystal);
mCrystal.
setColor(GameConsts.
PINGK_COLOR);
for (int i =
0; i
< NUM_SHARD_SPRITES
; i++
)
{
mShardSprites
[i
] =
new Sprite2D
();
mShardSprites
[i
].
init(mShardSpriteIds
[i
]);
}
}
public void update
(float deltaTime
)
{
Ball ball = mGameLogic.
getBall();
int i =
0;
while (i
< mParticles.
size())
{
Particle p = mParticles.
get(i
);
p.
update(deltaTime
);
// check destruction
if (p.
isInside(ball.
getX(), ball.
getY()) && !p.
isInside(ball.
getLastX(), ball.
getLastY()))
{
// reflect
Vector2 normal =
new Vector2
(ball.
getX() - p.
x, ball.
getY() - p.
y);
float angle = normal.
getAngle();
ball.
reflectAlongNormal(angle
);
// destroy
spawnShards
(p.
x, p.
y);
// remove
mParticles.
remove(i
);
// play sound
mGameLogic.
playSound(R.
raw.
crystal1);
// add hit
mGameLogic.
getCrystalHitCounter().
addHit(p.
x, p.
y);
continue;
}
i++
;
}
i =
0;
while (i
< mShards.
size())
{
Shard s = mShards.
get(i
);
s.
update(deltaTime
);
if (s.
isDone())
{
mShards.
remove(i
);
continue;
}
i++
;
}
}
public void render
()
{
for (int i = mParticles.
size()-
1; i
>=
0; i--
)
{
mParticles.
get(i
).
render();
}
for (int i =
0; i
< mShards.
size(); i++
)
{
mShards.
get(i
).
render();
}
}
public void spawnCrystal
(float posX,
float posY, Vector2 direction
)
{
if (mParticles.
size() < GameConsts.
POWERUP_CRYSTAL_MAX_PARTICLES)
{
float regrowthTime = mGameLogic.
getRandomFloat(GameConsts.
POWERUP_CRYSTAL_PARTICLE_GROWTH_TIME_MIN, GameConsts.
POWERUP_CRYSTAL_PARTICLE_GROWTH_TIME_MIN);
Particle p =
new Particle
(posX, posY, direction, regrowthTime
);
mParticles.
add(p
);
}
}
public void destroyCrystals
()
{
if (mParticles.
size() > 0)
mGameLogic.
playSound(R.
raw.
crystal2);
for (int i =
0; i
< mParticles.
size(); i++
)
{
Particle p = mParticles.
get(i
);
spawnShards
(p.
x, p.
y);
}
mParticles.
clear();
}
public Particle findCrystalAt
(float posX,
float posY,
float maxDistance
)
{
for (int i =
0; i
< mParticles.
size(); i++
)
{
Particle p = mParticles.
get(i
);
if (p.
distanceFrom(posX, posY
) <= maxDistance
)
return p
;
}
return null;
}
public Particle findCrystalAt
(float posX,
float posY
)
{
return findCrystalAt
(posX, posY, 0.0f
);
}
public void spawnShards
(float posX,
float posY
)
{
// spawn multiple shards
for (int i =
0; i
< GameConsts.
POWERUP_CRYSTAL_MAX_SHARDS; i++
)
{
int whichSprite = mGameLogic.
getRandomizer().
nextInt(NUM_SHARD_SPRITES
);
float x = posX + mGameLogic.
getRandomFloat(-GameConsts.
POWERUP_CRYSTAL_SHARDS_SPREAD, GameConsts.
POWERUP_CRYSTAL_SHARDS_SPREAD);
float y = posY + mGameLogic.
getRandomFloat(-GameConsts.
POWERUP_CRYSTAL_SHARDS_SPREAD, GameConsts.
POWERUP_CRYSTAL_SHARDS_SPREAD);
Vector2 direction = Vector2.
fromRotation(mGameLogic.
getRandomFloat(0.0f, 360.0f
));
direction.
setLength(GameConsts.
POWERUP_CRYSTAL_SHARDS_SPREAD_SPEED);
float size = mGameLogic.
getRandomFloat(GameConsts.
POWERUP_CRYSTAL_SHARDS_MIN_SIZE, GameConsts.
POWERUP_CRYSTAL_SHARDS_MAX_SIZE);
mShards.
add(new Shard
(x, y, whichSprite, direction, size
));
}
}
public int getNumCrystals
()
{
return mParticles.
size();
}
}