asteroid-game/jni/main_code.cpp

567 lines
14 KiB
C++
Raw Normal View History

2013-05-27 20:14:29 +00:00
#include "main_code.h"
#ifdef TARGET_ANDROID
#include "android_api.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include "include/Engine.h"
#include "main_code.h"
//Better move those to external config or something...
const cardinal CONST_LASER_TIMER = 200;
const int CONST_HIT_SCORE_POINTS = 100;
const float CONST_TIME_SCALE = 0.01f;
const float CONST_PLAYER_ACCELERATION = 3.f;
const float CONST_VELOCITY_FADE = 0.95f;
const float CONST_LASER_VELOCITY = 100.f;
const vec2 CONST_PLAYER_HALF_SIZE(30.f, 30.f);
const vec2 CONST_LASER_HALF_SIZE(10.f, 10.f);
const vec2 CONST_AST_POS1(40, 40);
const vec2 CONST_AST_POS2(40, 280);
const vec2 CONST_AST_POS3(440, 160);
float HealthToScale(int health)
{
return 0.5f + health * 0.3f;
}
float HealthToHitDistance(int health)
{
const float CONST_HIT_DISTANCE = 15.f;
return max(CONST_HIT_DISTANCE * HealthToScale(health), 10.f);
}
void TMyApplication::InnerInit()
{
*Console<<"Inner init go!\n";
#ifdef TARGET_ANDROID
ST::PathToResources = "";
#endif
#ifdef TARGET_WIN32
#ifdef NDEBUG
ST::PathToResources = "assets/";
#else
ST::PathToResources = "../../../assets/";
#endif
#endif
#ifdef TARGET_IOS
ST::PathToResources = "assets/";
#endif
RandomGenerator.seed(static_cast<unsigned int>(std::time(0)));
TapIsDown = false;
ResourceManager->TexList.AddTexture(CONST_CONSOLE_TEX_NAME);
ResourceManager->ShaderManager.AddShader("DefaultShader", "gui_transparent.vertex", "gui_transparent.fragment");
Renderer->PushShader("DefaultShader");
ResourceManager->FontManager.AddFont("droid_sans14", "droid_sans14_font_bitmap.bmp32", "droid_sans14_font_charmap.txt");
ResourceManager->FontManager.PushFont("droid_sans14");
ResourceManager->TexList.Serialize(*FileToPropertyTree("textures.xml"));
Renderer->PushProjectionMatrix(Renderer->GetScreenWidth(), Renderer->GetScreenHeight());
Level = 1;
Score = 0;
InitLevel();
Player.RenderPair.first.SamplerMap[CONST_STRING_TEXTURE_UNIFORM] = "shipTexture";
Player.RenderPair.second.Data = MakeDataTriangleList(Player.Pos - CONST_PLAYER_HALF_SIZE, Player.Pos + CONST_PLAYER_HALF_SIZE);
Player.RenderPair.second.RefreshBuffer();
BackgroundRenderPair.first.SamplerMap[CONST_STRING_TEXTURE_UNIFORM] = "backgroundTexture";
BackgroundRenderPair.second.Data = MakeDataTriangleList(vec2(0,0), vec2(Renderer->GetScreenWidth(), Renderer->GetScreenHeight()));
BackgroundRenderPair.second.RefreshBuffer();
*Console<<"Inner init end!\n";
glDepthFunc(GL_LEQUAL);
}
void TMyApplication::InnerDeinit()
{
}
void TMyApplication::InnerDraw()
{
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Draw background
TRenderParamsSetter renderParamSetter(BackgroundRenderPair.first);
Renderer->DrawTriangleList(BackgroundRenderPair.second);
//Draw asteroids
BOOST_FOREACH(CAsteroidStruct& asteroid, Asteroids)
{
TRenderParamsSetter renderParamSetter(asteroid.RenderPair.first);
Renderer->DrawTriangleList(asteroid.RenderPair.second);
}
//Draw player
if (GameState != GS_LOST)
{
TRenderParamsSetter renderParamSetter(Player.RenderPair.first);
Renderer->DrawTriangleList(Player.RenderPair.second);
}
//Draw lasers
BOOST_FOREACH(CLaserStruct& laser, Lasers)
{
TRenderParamsSetter renderParamSetter(laser.RenderPair.first);
Renderer->DrawTriangleList(laser.RenderPair.second);
}
//Draw texts
glBindTexture(GL_TEXTURE_2D, ResourceManager->TexList[ResourceManager->FontManager.GetCurrentFontTextureName()]);
Renderer->DrawTriangleList(LevelScoreText);
Renderer->DrawTriangleList(LevelMessageText);
}
void TMyApplication::InnerUpdate(cardinal dt)
{
float scaledTime = CONST_TIME_SCALE * dt;
//Update Asteroids
BOOST_FOREACH(CAsteroidStruct& asteroid, Asteroids)
{
float difAngle = asteroid.AngularVelocity * scaledTime;
asteroid.Angle += difAngle;
mat3 rotationMatrix = CreateZRotationMatrix(difAngle);
MoveDataTriangleList(asteroid.RenderPair.second.Data, -vec3(asteroid.CenterPos, 0));
RotateDataTriangleList(asteroid.RenderPair.second.Data, rotationMatrix);
MoveDataTriangleList(asteroid.RenderPair.second.Data, vec3(asteroid.CenterPos, 0));
vec2 dif = asteroid.Velocity * scaledTime;
vec2 newCenterPos = NormalizePos(asteroid.CenterPos + dif);
dif = newCenterPos - asteroid.CenterPos;
asteroid.CenterPos = newCenterPos;
MoveDataTriangleList(asteroid.RenderPair.second.Data, vec3(dif, 0));
asteroid.RenderPair.second.RefreshBuffer();
}
UpdatePlayerPosition(scaledTime);
//Shoot laser
LaserTimer.Update(dt);
if (LaserTimer.IsOver())
{
LaserTimer.SetTimer(CONST_LASER_TIMER);
if (GameState == GS_PLAY)
{
AddNewLaser();
}
}
//Update lasers
BOOST_FOREACH(CLaserStruct& laser, Lasers)
{
vec2 dif = CONST_LASER_VELOCITY *laser.Dir * scaledTime;
MoveDataTriangleList(laser.RenderPair.second.Data, vec3(dif, 0));
laser.Pos += dif;
laser.RenderPair.second.RefreshBuffer();
}
//Do all checks...
ProcessLaserHit();
ProcessPlayerCollisions();
ClearUnusedLasers();
if (Asteroids.size() == 0 && GameState == GS_PLAY)
{
GameState = GS_WON;
RefreshScoreText();
}
}
void TMyApplication::InnerOnTapDown(vec2 p)
{
TapIsDown = true;
LastTap = p;
}
void TMyApplication::InnerOnTapUp(vec2 p)
{
TapIsDown = false;
if (GameState == GS_LOST)
{
Level = 1;
Score = 0;
InitLevel();
}
else if (GameState == GS_WON)
{
Level++;
InitLevel();
}
}
void TMyApplication::InnerOnTapUpAfterMove(vec2 p)
{
TapIsDown = false;
}
void TMyApplication::InnerOnMove(vec2 shift)
{
LastTap -= shift;
}
void TMyApplication::InitLevel()
{
GameState = GS_PLAY;
LaserTimer.SetTimer(CONST_LASER_TIMER);
Asteroids.clear();
Lasers.clear();
CreateRandomAsteroid(CONST_AST_POS1, Level);
CreateRandomAsteroid(CONST_AST_POS2, Level);
CreateRandomAsteroid(CONST_AST_POS3, Level);
Player.Angle = 0;
Player.Pos = vec2(Renderer->GetScreenWidth()/2, Renderer->GetScreenHeight()/2);
RefreshScoreText();
}
CAsteroidStruct TMyApplication::CreateAsteroid(vec2 pos, vec2 dir, int health)
{
static const float CONST_TEX_COORD_SCALE = 0.01f;
static const float CONST_ANGULAR_VELOCITY_SCALE = 0.001f;
static const boost::random::uniform_int_distribution<> velocityDistribution(5, 10);
static const boost::random::uniform_int_distribution<> angularVelocityDistribution(0, 10);
static const boost::random::uniform_int_distribution<> vertexNumberDistribution(5, 10);
static const boost::random::uniform_int_distribution<> vertexShiftDistribution(20, 30);
CAsteroidStruct result;
result.Health = health;
result.CenterPos = pos;
result.Angle = 0;
result.AngularVelocity = angularVelocityDistribution(RandomGenerator) * CONST_ANGULAR_VELOCITY_SCALE;
result.Velocity = velocityDistribution(RandomGenerator) * dir;
int numberOfVertices = vertexNumberDistribution(RandomGenerator);
std::vector<float> distArr(numberOfVertices);
for (int i=0; i<numberOfVertices; i++)
{
distArr[i] = vertexShiftDistribution(RandomGenerator) * HealthToScale(health);
}
//First iteration
vec2 prevShift = distArr[0] * vec2(1,0);
vec2 prevTexCoordShift = prevShift * CONST_TEX_COORD_SCALE;
//Other iterations
for (int i = 1; i <= numberOfVertices; i++)
{
float angle = i * 2 * pi / static_cast<float>(numberOfVertices);
vec2 shift = distArr[i % numberOfVertices] * vec2(cosf(angle), sinf(angle));
vec2 texCoordShift = shift * CONST_TEX_COORD_SCALE;
result.RenderPair.second.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB].push_back(vec3(pos, 0));
result.RenderPair.second.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB].push_back(vec3(pos + prevShift, 0));
result.RenderPair.second.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB].push_back(vec3(pos + shift, 0));
result.RenderPair.second.Data.Vec2CoordArr[CONST_STRING_TEXCOORD_ATTRIB].push_back(vec2(0.5f, 0.5f));
result.RenderPair.second.Data.Vec2CoordArr[CONST_STRING_TEXCOORD_ATTRIB].push_back(vec2(0.5f, 0.5f) + prevTexCoordShift);
result.RenderPair.second.Data.Vec2CoordArr[CONST_STRING_TEXCOORD_ATTRIB].push_back(vec2(0.5f, 0.5f) + texCoordShift);
prevShift = shift;
prevTexCoordShift = texCoordShift;
}
result.RenderPair.first.SamplerMap[CONST_STRING_TEXTURE_UNIFORM] = "asteroidTexture";
result.RenderPair.second.RefreshBuffer();
return result;
}
void TMyApplication::CreateRandomAsteroid(vec2 pos, int health)
{
static const boost::random::uniform_int_distribution<> angleDistribution(0, 36);
float randomAngle = angleDistribution(RandomGenerator) * pi / 18.f;
Asteroids.push_back(CreateAsteroid(pos, vec2(cosf(randomAngle), sinf(randomAngle)), health));
}
void TMyApplication::CreateAsteroidParts(vec2 pos, int newHealth)
{
static const boost::random::uniform_int_distribution<> CreateAsteroidParts(2, 5);
static const boost::random::uniform_int_distribution<> angleDistribution(0, 36);
float randomAngle = angleDistribution(RandomGenerator) * pi / 18.f;
int number = CreateAsteroidParts(RandomGenerator);
for (int i = 0; i < number; i++)
{
float partAngle = randomAngle + i * 2 * pi / static_cast<float>(number);
Asteroids.push_back(CreateAsteroid(pos, vec2(cosf(partAngle), sinf(partAngle)), newHealth));
}
}
vec2 TMyApplication::NormalizePos(vec2 pos)
{
vec2 result = pos;
while (result.v[0] < 0)
{
result.v[0] += Renderer->GetScreenWidth();
}
while (result.v[1] < 0)
{
result.v[1] += Renderer->GetScreenHeight();
}
while (result.v[0] >= Renderer->GetScreenWidth())
{
result.v[0] -= Renderer->GetScreenWidth();
}
while (result.v[1] >= Renderer->GetScreenHeight())
{
result.v[1] -= Renderer->GetScreenHeight();
}
return result;
}
void TMyApplication::RefreshPlayerPos()
{
Replace6PointsInTriangleList(Player.RenderPair.second.Data, 0, (-1) * CONST_PLAYER_HALF_SIZE, CONST_PLAYER_HALF_SIZE);
mat3 rotationMatrix = CreateZRotationMatrix(Player.Angle);
RotateDataTriangleList(Player.RenderPair.second.Data, rotationMatrix);
MoveDataTriangleList(Player.RenderPair.second.Data, vec3(Player.Pos, 0));
Player.RenderPair.second.RefreshBuffer();
}
void TMyApplication::AddNewLaser()
{
CLaserStruct laser;
float angle = Player.Angle;
laser.Dir = vec2(cosf(angle), sinf(angle));
laser.Pos = Player.Pos;
laser.RenderPair.second.Data = MakeDataTriangleList((-1) * CONST_LASER_HALF_SIZE, CONST_LASER_HALF_SIZE);
mat3 rotationMatrix = CreateZRotationMatrix(angle);
RotateDataTriangleList(laser.RenderPair.second.Data, rotationMatrix);
MoveDataTriangleList(laser.RenderPair.second.Data, vec3(laser.Pos, 0));
laser.RenderPair.first.SamplerMap[CONST_STRING_TEXTURE_UNIFORM] = "fireTexture";
laser.RenderPair.second.RefreshBuffer();
Lasers.push_back(laser);
}
void TMyApplication::UpdatePlayerPosition(float scaledTime)
{
if (TapIsDown)
{
vec2 dir = Normalize(LastTap - Player.Pos);
Player.Velocity += CONST_PLAYER_ACCELERATION * scaledTime * dir;
Player.Angle = acosf(DotProduct(dir, vec2(1, 0)));
if (dir.v[1] < 0)
{
Player.Angle = -Player.Angle;
}
}
Player.Pos += Player.Velocity * scaledTime;
Player.Velocity *= powf(CONST_VELOCITY_FADE, clamp(scaledTime, 0.f, 1.5f));
Player.Pos = NormalizePos(Player.Pos);
RefreshPlayerPos();
}
void TMyApplication::ProcessLaserHit()
{
for (auto laserItr = Lasers.begin(); laserItr != Lasers.end(); )
{
for (auto astItr = Asteroids.begin(); astItr != Asteroids.end(); )
{
float realDistance = HealthToHitDistance(astItr->Health);
if (fabs(laserItr->Pos.v[0] - astItr->CenterPos.v[0]) < realDistance &&
fabs(laserItr->Pos.v[1] - astItr->CenterPos.v[1]) < realDistance)
{
laserItr = Lasers.erase(laserItr);
if (astItr->Health > 0)
{
CreateAsteroidParts(astItr->CenterPos, astItr->Health - 1);
}
astItr = Asteroids.erase(astItr);
Score += CONST_HIT_SCORE_POINTS;
RefreshScoreText();
break;
}
if (astItr != Asteroids.end())
{
astItr++;
}
}
if (laserItr != Lasers.end())
{
laserItr++;
}
}
}
void TMyApplication::ProcessPlayerCollisions()
{
for (auto astItr = Asteroids.begin(); astItr != Asteroids.end(); astItr++)
{
float realDistance = HealthToHitDistance(astItr->Health);
if (fabs(astItr->CenterPos.v[0] - Player.Pos.v[0]) < realDistance && fabs(astItr->CenterPos.v[1] - Player.Pos.v[1]) < realDistance)
{
GameState = GS_LOST;
RefreshScoreText();
}
}
}
void TMyApplication::ClearUnusedLasers()
{
for (auto itr = Lasers.begin(); itr != Lasers.end(); )
{
if (itr->Pos.v[0] < 0 || itr->Pos.v[1] < 0 || itr->Pos.v[0] > Renderer->GetScreenWidth() || itr->Pos.v[1] > Renderer->GetScreenHeight())
{
itr = Lasers.erase(itr);
}
if (itr != Lasers.end())
{
itr++;
}
}
}
void TMyApplication::RefreshScoreText()
{
LevelScoreText = ResourceManager->FontManager.DrawStringToVBO(vec2(10, 20), TTextBasicAreaParams(), "Score: "+ tostr(Score));
if (GameState == GS_PLAY)
{
LevelMessageText = ResourceManager->FontManager.DrawStringToVBO(vec2(10, 300), TTextBasicAreaParams(), "Now playing "+ tostr(Level) + " level");
}
else if (GameState == GS_WON)
{
LevelMessageText = ResourceManager->FontManager.DrawStringToVBO(vec2(10, 300), TTextBasicAreaParams(), "You won! Tap on screen to start next level");
}
else if (GameState == GS_LOST)
{
LevelMessageText = ResourceManager->FontManager.DrawStringToVBO(vec2(10, 300), TTextBasicAreaParams(), "You failed! Tap on screen to restart");
}
}