|
|
@ -87,16 +87,20 @@ void FaceBall::LoadLevel(int level) |
|
|
|
objects.clear(); |
|
|
|
objects.clear(); |
|
|
|
bullets.clear(); |
|
|
|
bullets.clear(); |
|
|
|
enemies.clear(); |
|
|
|
enemies.clear(); |
|
|
|
|
|
|
|
vi2d exitCoords = { 0,0 }; |
|
|
|
for (int y = 0; y < MAP_SIZE.y; y++) { |
|
|
|
for (int y = 0; y < MAP_SIZE.y; y++) { |
|
|
|
std::vector<MapSquare>row; |
|
|
|
std::vector<MapSquare>row; |
|
|
|
for (int x = 0; x < MAP_SIZE.x; x++) { |
|
|
|
for (int x = 0; x < MAP_SIZE.x; x++) { |
|
|
|
row.push_back({}); |
|
|
|
row.push_back({}); |
|
|
|
mapFloor.tris.push_back({ {{(float)x,0,(float)y},{(float)x,0,(float)y + 1},{(float)x + 1,0,(float)y}},{{0,0},{0,1},{1,0}},{WHITE,WHITE,WHITE} }); |
|
|
|
mapFloor.tris.push_back({ {{(float)x,0,(float)y},{(float)x,0,(float)y + 1},{(float)x + 1,0,(float)y}},{{0,0},{0,1},{1,0}},{WHITE,WHITE,WHITE}, floor_tex }); |
|
|
|
mapFloor.tris.push_back({ {{(float)x + 1,0,(float)y},{(float)x,0,(float)y + 1},{(float)x + 1,0,(float)y + 1}},{{1,0},{0,1},{1,1}},{WHITE,WHITE,WHITE} }); |
|
|
|
mapFloor.tris.push_back({ {{(float)x + 1,0,(float)y},{(float)x,0,(float)y + 1},{(float)x + 1,0,(float)y + 1}},{{1,0},{0,1},{1,1}},{WHITE,WHITE,WHITE}, floor_tex }); |
|
|
|
EnemyID id = mapData[y][x].enemyId; |
|
|
|
EnemyID id = mapData[y][x].enemyId; |
|
|
|
if (id>=SHOOTME&& id < COIN) { |
|
|
|
if (id>=SHOOTME&& id < COIN) { |
|
|
|
enemies.push_back({ id,vec3d{x + 0.5f,0,y + 0.5f},((int)mapData[y][x].facingDir-1)*PI/2,0.2f}); |
|
|
|
enemies.push_back({ id,vec3d{x + 0.5f,0,y + 0.5f},((int)mapData[y][x].facingDir-1)*PI/2,0.2f}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (id == EXIT) { |
|
|
|
|
|
|
|
exitCoords = { x,y }; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
map.push_back(row); |
|
|
|
map.push_back(row); |
|
|
|
} |
|
|
|
} |
|
|
@ -117,25 +121,42 @@ void FaceBall::LoadLevel(int level) |
|
|
|
} |
|
|
|
} |
|
|
|
AddWall(wallData, { x,y }); |
|
|
|
AddWall(wallData, { x,y }); |
|
|
|
if (map[y][x].wallN != NULL) { |
|
|
|
if (map[y][x].wallN != NULL) { |
|
|
|
mapWalls.tris.push_back({ {{(float)x,1,(float)y},{(float)x,0,(float)y},{(float)x + 1,1,(float)y}},{{0,0},{0,1},{1,0}},{WHITE,WHITE,WHITE} }); |
|
|
|
Decal*exitWallTex = wall_tex; |
|
|
|
mapWalls.tris.push_back({ {{(float)x,0,(float)y},{(float)x + 1,0,(float)y},{(float)x + 1,1,(float)y}},{{0,1},{1,1},{1,0}},{WHITE,WHITE,WHITE} }); |
|
|
|
if (vi2d{ x,y } == vi2d{exitCoords.x, exitCoords.y + 1}) { |
|
|
|
|
|
|
|
exitWallTex = exit_wall_tex; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
mapWalls.tris.push_back({ {{(float)x,1,(float)y},{(float)x,0,(float)y},{(float)x + 1,1,(float)y}},{{0,0},{0,1},{1,0}},{WHITE,WHITE,WHITE}, exitWallTex }); |
|
|
|
|
|
|
|
mapWalls.tris.push_back({ {{(float)x,0,(float)y},{(float)x + 1,0,(float)y},{(float)x + 1,1,(float)y}},{{0,1},{1,1},{1,0}},{WHITE,WHITE,WHITE}, exitWallTex }); |
|
|
|
} |
|
|
|
} |
|
|
|
if (map[y][x].wallS != NULL) { |
|
|
|
if (map[y][x].wallS != NULL) { |
|
|
|
mapWalls.tris.push_back({ {{(float)x + 1,1,(float)y + 1},{(float)x,0,(float)y + 1},{(float)x,1,(float)y + 1}},{{0,0},{1,1},{1,0}},{WHITE,WHITE,WHITE} }); |
|
|
|
Decal* exitWallTex = wall_tex; |
|
|
|
mapWalls.tris.push_back({ {{(float)x + 1,1,(float)y + 1},{(float)x + 1,0,(float)y + 1},{(float)x,0,(float)y + 1}},{{0,0},{0,1},{1,1}},{WHITE,WHITE,WHITE} }); |
|
|
|
if (vi2d{ x,y } == vi2d{ exitCoords.x, exitCoords.y - 1 }) { |
|
|
|
|
|
|
|
exitWallTex = exit_wall_tex; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
mapWalls.tris.push_back({ {{(float)x + 1,1,(float)y + 1},{(float)x,0,(float)y + 1},{(float)x,1,(float)y + 1}},{{0,0},{1,1},{1,0}},{WHITE,WHITE,WHITE}, exitWallTex }); |
|
|
|
|
|
|
|
mapWalls.tris.push_back({ {{(float)x + 1,1,(float)y + 1},{(float)x + 1,0,(float)y + 1},{(float)x,0,(float)y + 1}},{{0,0},{0,1},{1,1}},{WHITE,WHITE,WHITE}, exitWallTex }); |
|
|
|
} |
|
|
|
} |
|
|
|
if (map[y][x].wallW != NULL) { |
|
|
|
if (map[y][x].wallW != NULL) { |
|
|
|
mapWalls.tris.push_back({ {{(float)x,1,(float)y},{(float)x,1,(float)y + 1}, {(float)x,0,(float)y + 1}},{{1,0},{0,0},{0,1}},{WHITE,WHITE,WHITE} }); |
|
|
|
Decal* exitWallTex = wall_tex; |
|
|
|
mapWalls.tris.push_back({ {{(float)x,0,(float)y},{(float)x,1,(float)y}, {(float)x,0,(float)y + 1}}, {{1,1},{1,0},{0,1}},{WHITE,WHITE,WHITE} }); |
|
|
|
if (vi2d{ x,y } == vi2d{ exitCoords.x+1, exitCoords.y }) { |
|
|
|
|
|
|
|
exitWallTex = exit_wall_tex; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
mapWalls.tris.push_back({ {{(float)x,1,(float)y},{(float)x,1,(float)y + 1}, {(float)x,0,(float)y + 1}},{{1,0},{0,0},{0,1}},{WHITE,WHITE,WHITE}, exitWallTex }); |
|
|
|
|
|
|
|
mapWalls.tris.push_back({ {{(float)x,0,(float)y},{(float)x,1,(float)y}, {(float)x,0,(float)y + 1}}, {{1,1},{1,0},{0,1}},{WHITE,WHITE,WHITE}, exitWallTex }); |
|
|
|
} |
|
|
|
} |
|
|
|
if (map[y][x].wallE != NULL) { |
|
|
|
if (map[y][x].wallE != NULL) { |
|
|
|
mapWalls.tris.push_back({ {{(float)x + 1,0,(float)y + 1},{(float)x + 1,1,(float)y + 1},{(float)x + 1,1,(float)y}},{{1,1},{1,0},{0,0}},{WHITE,WHITE,WHITE} }); |
|
|
|
Decal* exitWallTex = wall_tex; |
|
|
|
mapWalls.tris.push_back({ {{(float)x + 1,0,(float)y + 1} ,{(float)x + 1,1,(float)y},{(float)x + 1,0,(float)y}},{{1,1},{0,0},{0,1}},{WHITE,WHITE,WHITE} }); |
|
|
|
if (vi2d{ x,y } == vi2d{ exitCoords.x - 1, exitCoords.y }) { |
|
|
|
|
|
|
|
exitWallTex = exit_wall_tex; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
mapWalls.tris.push_back({ {{(float)x + 1,0,(float)y + 1},{(float)x + 1,1,(float)y + 1},{(float)x + 1,1,(float)y}},{{1,1},{1,0},{0,0}},{WHITE,WHITE,WHITE}, exitWallTex }); |
|
|
|
|
|
|
|
mapWalls.tris.push_back({ {{(float)x + 1,0,(float)y + 1} ,{(float)x + 1,1,(float)y},{(float)x + 1,0,(float)y}},{{1,1},{0,0},{0,1}},{WHITE,WHITE,WHITE}, exitWallTex }); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
objects.push_back({ mapWalls,{0,0},0,0 }); |
|
|
|
objects.push_back({ mapWalls,{0,0,0},0,0 }); |
|
|
|
objects.push_back({ mapFloor,{0,0},0,0 }); |
|
|
|
objects.push_back({ mapFloor,{0,0,0},0,0 }); |
|
|
|
|
|
|
|
objects.push_back({ game->mapExit,{(float)exitCoords.x+0.5f,0,(float)exitCoords.y+0.5f},0,0.4f }); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool FaceBall::CheckCollision(vec3d movementVector,vf2d pos,float radius){ |
|
|
|
bool FaceBall::CheckCollision(vec3d movementVector,vf2d pos,float radius){ |
|
|
@ -540,6 +561,7 @@ void FaceBall::RenderMesh(mat4x4&matView,std::vector<Triangle>&vecTrianglesToRas |
|
|
|
triTransformed.col[0] = tri.col[0]; |
|
|
|
triTransformed.col[0] = tri.col[0]; |
|
|
|
triTransformed.col[1] = tri.col[1]; |
|
|
|
triTransformed.col[1] = tri.col[1]; |
|
|
|
triTransformed.col[2] = tri.col[2]; |
|
|
|
triTransformed.col[2] = tri.col[2]; |
|
|
|
|
|
|
|
triTransformed.tex = tri.tex; |
|
|
|
|
|
|
|
|
|
|
|
vec3d normal, line1, line2; |
|
|
|
vec3d normal, line1, line2; |
|
|
|
line1 = Vector_Sub(triTransformed.p[1], triTransformed.p[0]); |
|
|
|
line1 = Vector_Sub(triTransformed.p[1], triTransformed.p[0]); |
|
|
@ -575,6 +597,7 @@ void FaceBall::RenderMesh(mat4x4&matView,std::vector<Triangle>&vecTrianglesToRas |
|
|
|
triViewed.col[0] = Pixel(triViewed.col[0].r * colorMult, triViewed.col[0].g * colorMult, triViewed.col[0].b * colorMult); |
|
|
|
triViewed.col[0] = Pixel(triViewed.col[0].r * colorMult, triViewed.col[0].g * colorMult, triViewed.col[0].b * colorMult); |
|
|
|
triViewed.col[1] = Pixel(triViewed.col[1].r * colorMult2, triViewed.col[1].g * colorMult2, triViewed.col[1].b * colorMult2); |
|
|
|
triViewed.col[1] = Pixel(triViewed.col[1].r * colorMult2, triViewed.col[1].g * colorMult2, triViewed.col[1].b * colorMult2); |
|
|
|
triViewed.col[2] = Pixel(triViewed.col[2].r * colorMult3, triViewed.col[2].g * colorMult3, triViewed.col[2].b * colorMult3); |
|
|
|
triViewed.col[2] = Pixel(triViewed.col[2].r * colorMult3, triViewed.col[2].g * colorMult3, triViewed.col[2].b * colorMult3); |
|
|
|
|
|
|
|
triViewed.tex = triTransformed.tex; |
|
|
|
|
|
|
|
|
|
|
|
for (Bullet& b : bullets) { |
|
|
|
for (Bullet& b : bullets) { |
|
|
|
float dist = std::sqrtf(std::powf(b.pos.x - triTransformed.p[0].x, 2) + std::powf(b.pos.y - triTransformed.p[0].y, 2) + std::powf(b.pos.z - triTransformed.p[0].z, 2)); |
|
|
|
float dist = std::sqrtf(std::powf(b.pos.x - triTransformed.p[0].x, 2) + std::powf(b.pos.y - triTransformed.p[0].y, 2) + std::powf(b.pos.z - triTransformed.p[0].z, 2)); |
|
|
@ -602,6 +625,7 @@ void FaceBall::RenderMesh(mat4x4&matView,std::vector<Triangle>&vecTrianglesToRas |
|
|
|
triProjected.col[0] = clipped[n].col[0]; |
|
|
|
triProjected.col[0] = clipped[n].col[0]; |
|
|
|
triProjected.col[1] = clipped[n].col[1]; |
|
|
|
triProjected.col[1] = clipped[n].col[1]; |
|
|
|
triProjected.col[2] = clipped[n].col[2]; |
|
|
|
triProjected.col[2] = clipped[n].col[2]; |
|
|
|
|
|
|
|
triProjected.tex = clipped[n].tex; |
|
|
|
triProjected.uv[0] = clipped[n].uv[0]; |
|
|
|
triProjected.uv[0] = clipped[n].uv[0]; |
|
|
|
triProjected.uv[1] = clipped[n].uv[1]; |
|
|
|
triProjected.uv[1] = clipped[n].uv[1]; |
|
|
|
triProjected.uv[2] = clipped[n].uv[2]; |
|
|
|
triProjected.uv[2] = clipped[n].uv[2]; |
|
|
@ -640,7 +664,6 @@ void FaceBall::RenderMesh(mat4x4&matView,std::vector<Triangle>&vecTrianglesToRas |
|
|
|
triProjected.p[1].y *= 0.5f * (float)ScreenHeight(); |
|
|
|
triProjected.p[1].y *= 0.5f * (float)ScreenHeight(); |
|
|
|
triProjected.p[2].x *= 0.5f * (float)ScreenWidth(); |
|
|
|
triProjected.p[2].x *= 0.5f * (float)ScreenWidth(); |
|
|
|
triProjected.p[2].y *= 0.5f * (float)ScreenHeight(); |
|
|
|
triProjected.p[2].y *= 0.5f * (float)ScreenHeight(); |
|
|
|
triProjected.tex = o.mesh.texture; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vecTrianglesToRaster.push_back(triProjected); |
|
|
|
vecTrianglesToRaster.push_back(triProjected); |
|
|
|
} |
|
|
|
} |
|
|
@ -684,8 +707,7 @@ void FaceBall::RenderWorld() { |
|
|
|
|
|
|
|
|
|
|
|
//std::sort(vecTrianglesToRaster.begin(),vecTrianglesToRaster.end(),[](triangle&t1,triangle&t2){return (t1.p[0].z+t1.p[1].z+t1.p[2].z)/3.0f>(t2.p[0].z+t2.p[1].z+t2.p[2].z)/3.0f;});
|
|
|
|
//std::sort(vecTrianglesToRaster.begin(),vecTrianglesToRaster.end(),[](triangle&t1,triangle&t2){return (t1.p[0].z+t1.p[1].z+t1.p[2].z)/3.0f>(t2.p[0].z+t2.p[1].z+t2.p[2].z)/3.0f;});
|
|
|
|
ClearBuffer(BLACK, true); |
|
|
|
ClearBuffer(BLACK, true); |
|
|
|
int triRenderCount = 0; |
|
|
|
triRenderCount = 0; |
|
|
|
|
|
|
|
|
|
|
|
for (auto& triToRaster : vecTrianglesToRaster) { |
|
|
|
for (auto& triToRaster : vecTrianglesToRaster) { |
|
|
|
|
|
|
|
|
|
|
|
Triangle clipped[2]; |
|
|
|
Triangle clipped[2]; |
|
|
@ -752,9 +774,6 @@ void FaceBall::RenderWorld() { |
|
|
|
triRenderCount++; |
|
|
|
triRenderCount++; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
SetDecalMode(DecalMode::NORMAL); |
|
|
|
|
|
|
|
DrawStringDecal({ 0,0 }, "Triangles: " + std::to_string(triRenderCount), WHITE, { 2,2 }); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FaceBall::HandleKeys(float fElapsedTime) { |
|
|
|
void FaceBall::HandleKeys(float fElapsedTime) { |
|
|
@ -846,6 +865,9 @@ void FaceBall::HandleKeys(float fElapsedTime) { |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
fYaw -= 2 * fElapsedTime; |
|
|
|
fYaw -= 2 * fElapsedTime; |
|
|
|
|
|
|
|
if (hudOffset < 20) { |
|
|
|
|
|
|
|
hudOffset = std::min(20.f, hudOffset + 128 * fElapsedTime); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (GetKey(olc::D).bHeld) { |
|
|
|
if (GetKey(olc::D).bHeld) { |
|
|
@ -854,6 +876,9 @@ void FaceBall::HandleKeys(float fElapsedTime) { |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
fYaw += 2 * fElapsedTime; |
|
|
|
fYaw += 2 * fElapsedTime; |
|
|
|
|
|
|
|
if (hudOffset > -20) { |
|
|
|
|
|
|
|
hudOffset = std::max(-20.f,hudOffset-128 * fElapsedTime); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (GetKey(olc::F1).bPressed) { |
|
|
|
if (GetKey(olc::F1).bPressed) { |
|
|
@ -902,10 +927,13 @@ bool FaceBall::OnUserCreate() |
|
|
|
bullet_tex = new Decal(new Sprite("assets/enemies/bullet.png")); |
|
|
|
bullet_tex = new Decal(new Sprite("assets/enemies/bullet.png")); |
|
|
|
floor_tex = new Decal(new Sprite("assets/floor.png")); |
|
|
|
floor_tex = new Decal(new Sprite("assets/floor.png")); |
|
|
|
enemy_Sonar_tex = new Decal(new Sprite("assets/enemies/Sonar.png")); |
|
|
|
enemy_Sonar_tex = new Decal(new Sprite("assets/enemies/Sonar.png")); |
|
|
|
|
|
|
|
hud = new Decal(new Sprite("assets/hud.png")); |
|
|
|
|
|
|
|
exit_wall_tex = new Decal(new Sprite("assets/exitwall.png")); |
|
|
|
|
|
|
|
|
|
|
|
enemy_ShootMe = { "assets/enemies/ShootMe.obj", enemy_ShootMe_tex }; |
|
|
|
enemy_ShootMe = { "assets/enemies/ShootMe.obj", enemy_ShootMe_tex }; |
|
|
|
enemy_Sonar = { "assets/enemies/Sonar.obj", enemy_Sonar_tex }; |
|
|
|
enemy_Sonar = { "assets/enemies/Sonar.obj", enemy_Sonar_tex }; |
|
|
|
bullet = { "assets/enemies/bullet.obj",bullet_tex }; |
|
|
|
bullet = { "assets/enemies/bullet.obj",bullet_tex }; |
|
|
|
|
|
|
|
mapExit = { "assets/Exit.obj",dot }; |
|
|
|
mapWalls.texture = wall_tex; |
|
|
|
mapWalls.texture = wall_tex; |
|
|
|
mapFloor.texture = floor_tex; |
|
|
|
mapFloor.texture = floor_tex; |
|
|
|
|
|
|
|
|
|
|
@ -937,6 +965,9 @@ bool Bullet::Update(float fElapsedTime) { |
|
|
|
Enemy& enemy = game->enemies[collided_enemy]; |
|
|
|
Enemy& enemy = game->enemies[collided_enemy]; |
|
|
|
if (!enemy.isDead()) { |
|
|
|
if (!enemy.isDead()) { |
|
|
|
enemy.Hurt(); |
|
|
|
enemy.Hurt(); |
|
|
|
|
|
|
|
if (enemy.isDead()) { |
|
|
|
|
|
|
|
game->SubtractTag(); |
|
|
|
|
|
|
|
} |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -951,6 +982,10 @@ bool Bullet::Update(float fElapsedTime) { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FaceBall::SubtractTag() { |
|
|
|
|
|
|
|
tagsRemaining = std::max(0, tagsRemaining - 1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void FaceBall::RunEnemyAI(Enemy& e,float fElapsedTime) { |
|
|
|
void FaceBall::RunEnemyAI(Enemy& e,float fElapsedTime) { |
|
|
|
if (e.isDead()) { |
|
|
|
if (e.isDead()) { |
|
|
|
if (!e.deathAnimationOver()) { |
|
|
|
if (!e.deathAnimationOver()) { |
|
|
@ -1023,6 +1058,18 @@ bool FaceBall::OnUserUpdate(float fElapsedTime) |
|
|
|
case GAME: { |
|
|
|
case GAME: { |
|
|
|
HandleKeys(fElapsedTime); |
|
|
|
HandleKeys(fElapsedTime); |
|
|
|
RenderWorld(); |
|
|
|
RenderWorld(); |
|
|
|
|
|
|
|
if (!GetKey(olc::D).bHeld && !GetKey(olc::A).bHeld) { |
|
|
|
|
|
|
|
hudOffsetAcc += 20 * fElapsedTime; |
|
|
|
|
|
|
|
while (hudOffsetAcc >= 1) { |
|
|
|
|
|
|
|
hudOffset /= 2; |
|
|
|
|
|
|
|
hudOffsetAcc--; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
SetDecalMode(DecalMode::NORMAL); |
|
|
|
|
|
|
|
DrawDecal({ -32+hudOffset,-18 }, hud, {1.05,1.05}); |
|
|
|
|
|
|
|
DrawStringDecal({ 112+hudOffset,4 }, "Triangles: " + std::to_string(triRenderCount), BLACK, { 2,4 }); |
|
|
|
|
|
|
|
std::string hudText = "Tags Left: " + std::to_string(tagsRemaining) + " Lives: " + std::to_string(lives); |
|
|
|
|
|
|
|
DrawStringPropDecal(vf2d{ hudOffset+(float)(ScreenWidth() / 2 - GetTextSizeProp(hudText).x * 3 / 2),(float)(ScreenHeight() - 64 - GetTextSizeProp(hudText).y*6) }, hudText, WHITE, {3,6}); |
|
|
|
}break; |
|
|
|
}break; |
|
|
|
case EDITOR: { |
|
|
|
case EDITOR: { |
|
|
|
editor.Update(fElapsedTime); |
|
|
|
editor.Update(fElapsedTime); |
|
|
@ -1047,7 +1094,6 @@ void FaceBall::OnTextEntryComplete(const std::string& sText) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main() |
|
|
|
int main() |
|
|
|
{ |
|
|
|
{ |
|
|
|
FaceBall demo; |
|
|
|
FaceBall demo; |
|
|
|