Clean up asteroids.

This commit is contained in:
Jonas 'Sortie' Termansen 2015-06-04 00:38:39 +02:00
parent ae1ed0c13c
commit 211bc0c5f2
1 changed files with 135 additions and 96 deletions

View File

@ -1,6 +1,6 @@
/******************************************************************************* /*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014, 2015.
This program is free software: you can redistribute it and/or modify it This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free under the terms of the GNU General Public License as published by the Free
@ -39,36 +39,34 @@
#include <dispd.h> #include <dispd.h>
const float PI = 3.1415926532f; static inline float RandomFloat()
inline float RandomFloat()
{ {
return arc4random() / (float) UINT32_MAX; return arc4random() / (float) UINT32_MAX;
} }
inline float RandomFloat(float min, float max) static inline float RandomFloat(float min, float max)
{ {
return min + RandomFloat() * (max - min); return min + RandomFloat() * (max - min);
} }
inline float DegreeToRadian(float degree) static inline float DegreeToRadian(float degree)
{ {
return degree / 180 * PI; return degree / 180 * M_PI;
} }
inline float RandomAngle() static inline float RandomAngle()
{ {
return RandomFloat() * DegreeToRadian(360); return RandomFloat() * DegreeToRadian(360);
} }
inline uint32_t MakeColor(uint8_t r, uint8_t g, uint8_t b) static inline uint32_t MakeColor(uint8_t r, uint8_t g, uint8_t b)
{ {
return b << 0UL | g << 8UL | r << 16UL; return b << 0UL | g << 8UL | r << 16UL;
} }
const size_t STARFIELD_WIDTH = 512UL; static const size_t STARFIELD_WIDTH = 512UL;
const size_t STARFIELD_HEIGHT = 512UL; static const size_t STARFIELD_HEIGHT = 512UL;
uint32_t starfield[STARFIELD_WIDTH * STARFIELD_HEIGHT]; static uint32_t starfield[STARFIELD_WIDTH * STARFIELD_HEIGHT];
void GenerateStarfield(uint32_t* bitmap, size_t width, size_t height) void GenerateStarfield(uint32_t* bitmap, size_t width, size_t height)
{ {
@ -85,10 +83,10 @@ void GenerateStarfield(uint32_t* bitmap, size_t width, size_t height)
} }
} }
const size_t MAXKEYNUM = 512UL; static const size_t MAXKEYNUM = 512UL;
bool keysdown[MAXKEYNUM] = { false }; static bool keysdown[MAXKEYNUM] = { false };
bool keyspending[MAXKEYNUM] = { false }; static bool keyspending[MAXKEYNUM] = { false };
struct timespec key_handled_last[MAXKEYNUM]; static struct timespec key_handled_last[MAXKEYNUM];
bool pop_is_key_just_down(int abskbkey) bool pop_is_key_just_down(int abskbkey)
{ {
@ -119,7 +117,8 @@ void FetchKeyboardInput()
const unsigned termmode = TERMMODE_KBKEY const unsigned termmode = TERMMODE_KBKEY
| TERMMODE_SIGNAL | TERMMODE_SIGNAL
| TERMMODE_NONBLOCK; | TERMMODE_NONBLOCK;
if ( settermmode(0, termmode) ) { error(1, errno, "settermmode"); } if ( settermmode(0, termmode) )
error(1, errno, "settermmode");
uint32_t codepoint; uint32_t codepoint;
ssize_t numbytes; ssize_t numbytes;
while ( 0 < (numbytes = read(0, &codepoint, sizeof(codepoint))) ) while ( 0 < (numbytes = read(0, &codepoint, sizeof(codepoint))) )
@ -137,15 +136,14 @@ void FetchKeyboardInput()
} }
} }
size_t xres; static size_t xres;
size_t yres; static size_t yres;
int fb; static size_t bpp;
size_t bpp; static size_t linesize;
size_t linesize; static size_t framesize;
size_t framesize; static uint32_t* buf;
uint32_t* buf; static bool gamerunning;
bool gamerunning; static unsigned long framenum;
unsigned long framenum;
void DrawLine(uint32_t color, long x0, long y0, long x1, long y1) void DrawLine(uint32_t color, long x0, long y0, long x1, long y1)
{ {
@ -162,10 +160,19 @@ void DrawLine(uint32_t color, long x0, long y0, long x1, long y1)
size_t index = y0 * linesize + x0; size_t index = y0 * linesize + x0;
buf[index] = color; buf[index] = color;
} }
if ( x0 == x1 && y0 == y1 ) { break; } if ( x0 == x1 && y0 == y1 )
break;
e2 = err; e2 = err;
if ( e2 > -dx ) { err -= dy; x0 += sx; } if ( e2 > -dx )
if ( e2 < dy ) { err += dx; y0 += sy; } {
err -= dy;
x0 += sx;
}
if ( e2 < dy )
{
err += dx;
y0 += sy;
}
} }
} }
@ -180,7 +187,11 @@ public:
Vector& operator=(const Vector& rhs) Vector& operator=(const Vector& rhs)
{ {
if ( this != &rhs ) { x = rhs.x; y = rhs.y; } if ( this != &rhs )
{
x = rhs.x;
y = rhs.y;
}
return *this; return *this;
} }
@ -265,7 +276,8 @@ public:
const Vector Normalize() const const Vector Normalize() const
{ {
float size = Size(); float size = Size();
if ( size == 0.0 ) { size = 1.0f; } if ( size == 0.0 )
size = 1.0f;
return *this / size; return *this / size;
} }
@ -302,10 +314,10 @@ class Object;
class Actor; class Actor;
class Spaceship; class Spaceship;
Object* firstobject = NULL; static Object* firstobject = NULL;
Object* lastobject = NULL; static Object* lastobject = NULL;
Vector screenoff; static Vector screenoff;
Spaceship* playership = NULL; static Spaceship* playership = NULL;
class Object class Object
{ {
@ -330,10 +342,14 @@ public:
virtual ~Object() virtual ~Object()
{ {
if ( !prevobj ) { firstobject = nextobj; } if ( !prevobj )
else { prevobj->nextobj = nextobj; } firstobject = nextobj;
if ( !nextobj ) { lastobject = prevobj; } else
else { nextobj->prevobj = prevobj; } prevobj->nextobj = nextobj;
if ( !nextobj )
lastobject = prevobj;
else
nextobj->prevobj = prevobj;
} }
public: public:
@ -405,7 +421,7 @@ public:
void Actor::Move(float deltatime) void Actor::Move(float deltatime)
{ {
acc = (force+otherforce) / mass; acc = (force + otherforce) / mass;
vel += acc * deltatime; vel += acc * deltatime;
pos += vel * deltatime; pos += vel * deltatime;
} }
@ -497,7 +513,8 @@ bool Asteroid::InsideMe(const Vector& p)
{ {
Vector from = Point(i) + pos; Vector from = Point(i) + pos;
Vector to = Point(i+1) + pos; Vector to = Point(i+1) + pos;
if ( InsideTriangle(from, to, center, p) ) { return true; } if ( InsideTriangle(from, to, center, p) )
return true;
} }
return false; return false;
} }
@ -518,7 +535,8 @@ void Asteroid::Render()
void Asteroid::OnHit() void Asteroid::OnHit()
{ {
if ( !GCIsAlive() ) { return; } if ( !GCIsAlive() )
return;
Vector axis = Vector(size/2.0f, 0.0f).Rotate(RandomAngle()); Vector axis = Vector(size/2.0f, 0.0f).Rotate(RandomAngle());
float sizea = RandomFloat(size*0.3, size*0.7); float sizea = RandomFloat(size*0.3, size*0.7);
float sizeb = RandomFloat(size*0.3, size*0.7); float sizeb = RandomFloat(size*0.3, size*0.7);
@ -561,7 +579,8 @@ void AsteroidField::Think(float /*deltatime*/)
Vector center = ((Actor*)playership)->pos; Vector center = ((Actor*)playership)->pos;
for ( Object* obj = firstobject; obj; obj = obj->NextObj() ) for ( Object* obj = firstobject; obj; obj = obj->NextObj() )
{ {
if ( !obj->IsA("Asteroid") ) { continue; } if ( !obj->IsA("Asteroid") )
continue;
Asteroid* ast = (Asteroid*) obj; Asteroid* ast = (Asteroid*) obj;
numasteroids++; numasteroids++;
float dist = ast->pos.DistanceTo(center); float dist = ast->pos.DistanceTo(center);
@ -613,10 +632,13 @@ void Missile::Think(float deltatime)
if ( ttl < 0 ) { GCDie(); } if ( ttl < 0 ) { GCDie(); }
for ( Object* obj = firstobject; obj; obj = obj->NextObj() ) for ( Object* obj = firstobject; obj; obj = obj->NextObj() )
{ {
if ( !obj->GCIsAlive() ) { continue; } if ( !obj->GCIsAlive() )
if ( !obj->IsA("Asteroid") ) { continue; } continue;
if ( !obj->IsA("Asteroid") )
continue;
Asteroid* ast = (Asteroid*) obj; Asteroid* ast = (Asteroid*) obj;
if ( !ast->InsideMe(pos) ) { continue; } if ( !ast->InsideMe(pos) )
continue;
ast->OnHit(); ast->OnHit();
GCDie(); GCDie();
} }
@ -680,14 +702,23 @@ void Attractor::Think(float deltatime)
float sofar = 2.5 * age; float sofar = 2.5 * age;
mass = sofar*sofar*sofar*sofar; mass = sofar*sofar*sofar*sofar;
size = age*age; size = age*age;
if ( 1.5*60 <= age ) { GCDie(); return; } if ( 1.5*60 <= age )
{
GCDie();
return;
}
for ( Object* obj = firstobject; obj; obj = obj->NextObj() ) for ( Object* obj = firstobject; obj; obj = obj->NextObj() )
{ {
if ( obj == this ) { continue; } if ( obj == this )
if ( !obj->GCIsAlive() ) { continue; } continue;
if ( !obj->IsA("Actor") ) { continue; } if ( !obj->GCIsAlive() )
if ( obj->IsA("Attractor") ) { continue; } continue;
//if ( obj->IsA("Spaceship") ) { continue; } if ( !obj->IsA("Actor") )
continue;
if ( obj->IsA("Attractor") )
continue;
//if ( obj->IsA("Spaceship") )
// continue;
Actor* other = (Actor*) obj; Actor* other = (Actor*) obj;
Vector relative = pos - other->pos; Vector relative = pos - other->pos;
float distsq = relative.SquaredSize(); float distsq = relative.SquaredSize();
@ -785,8 +816,10 @@ void Spaceship::Think(float deltatime)
{ {
for ( Object* obj = firstobject; obj; obj = obj->NextObj() ) for ( Object* obj = firstobject; obj; obj = obj->NextObj() )
{ {
if ( !obj->GCIsAlive() ) { continue; } if ( !obj->GCIsAlive() )
if ( !obj->IsA("Asteroid") ) { continue; } continue;
if ( !obj->IsA("Asteroid") )
continue;
Asteroid* ast = (Asteroid*) obj; Asteroid* ast = (Asteroid*) obj;
bool iscrystal = ast->Type() == TYPE_CRYSTAL; bool iscrystal = ast->Type() == TYPE_CRYSTAL;
bool isinside = false; bool isinside = false;
@ -794,8 +827,10 @@ void Spaceship::Think(float deltatime)
{ {
Vector relative = pos - ast->pos; Vector relative = pos - ast->pos;
float distsq = relative.SquaredSize(); float distsq = relative.SquaredSize();
if ( distsq < 4.0 * 4.0 ) { isinside = true; } if ( distsq < 4.0 * 4.0 )
if ( distsq < 100 ) { distsq = 100; } isinside = true;
if ( distsq < 100 )
distsq = 100;
float constant = 2000.0; float constant = 2000.0;
float forcesize = constant * mass * ast->mass / distsq; float forcesize = constant * mass * ast->mass / distsq;
Vector force = relative.Normalize() * forcesize; Vector force = relative.Normalize() * forcesize;
@ -823,16 +858,21 @@ void Spaceship::Think(float deltatime)
} }
const float turnspeed = 100.0; const float turnspeed = 100.0;
const float turnamount = turnspeed * deltatime; const float turnamount = turnspeed * deltatime;
if ( turnleft ) { shipangle -= DegreeToRadian(turnamount); } if ( turnleft )
if ( turnright ) { shipangle += DegreeToRadian(turnamount); } shipangle -= DegreeToRadian(turnamount);
if ( turnright )
shipangle += DegreeToRadian(turnamount);
float shipaccelamount = 15.0; float shipaccelamount = 15.0;
float shipaccel = 0.0; float shipaccel = 0.0;
if ( moveforward ) { shipaccel += shipaccelamount; } if ( moveforward )
if ( movebackward ) { shipaccel -= shipaccelamount; } shipaccel += shipaccelamount;
if ( movebackward )
shipaccel -= shipaccelamount;
force += Vector(shipaccel, 0.0).Rotate(shipangle) * mass; force += Vector(shipaccel, 0.0).Rotate(shipangle) * mass;
float shipspeed = vel.Size(); float shipspeed = vel.Size();
float maxspeed = 50.0f; float maxspeed = 50.0f;
//if ( maxspeed < shipspeed ) { vel *= maxspeed / shipspeed; } //if ( maxspeed < shipspeed )
// vel *= maxspeed / shipspeed;
if ( maxspeed < shipspeed ) if ( maxspeed < shipspeed )
{ {
Vector backforce = vel.Normalize() * -shipaccelamount * mass; Vector backforce = vel.Normalize() * -shipaccelamount * mass;
@ -845,17 +885,18 @@ void Spaceship::Think(float deltatime)
const Vector P3(16.0f, 0.0f); const Vector P3(16.0f, 0.0f);
Vector spawnpos = pos + P3.Rotate(shipangle) * 1.1; Vector spawnpos = pos + P3.Rotate(shipangle) * 1.1;
Vector spawnvel = Vector(speed, 0.0).Rotate(shipangle); Vector spawnvel = Vector(speed, 0.0).Rotate(shipangle);
if ( missile ) new Missile(spawnpos, vel + spawnvel, spawnvel, ttl); if ( missile )
if ( firework ) new Firework(spawnpos, vel + spawnvel, spawnvel, 0.0); new Missile(spawnpos, vel + spawnvel, spawnvel, ttl);
if ( attractor ) new Attractor(spawnpos, vel + spawnvel, 10000.0, 1.001); if ( firework )
new Firework(spawnpos, vel + spawnvel, spawnvel, 0.0);
if ( attractor )
new Attractor(spawnpos, vel + spawnvel, 10000.0, 1.001);
} }
} }
void Spaceship::Render() void Spaceship::Render()
{ {
Vector screenpos = pos - screenoff; Vector screenpos = pos - screenoff;
// TODO: Ideally these should be global constants, but global constructors
// are _not_ called upon process initiazation on Sortix yet.
const Vector P1(-8.0f, 8.0f); const Vector P1(-8.0f, 8.0f);
const Vector P2(-8.0f, -8.0f); const Vector P2(-8.0f, -8.0f);
const Vector P3(16.0f, 0.0f); const Vector P3(16.0f, 0.0f);
@ -917,8 +958,13 @@ Botship::Botship(float shipangle, Vector pos, Vector vel, Vector acc)
this->vel = vel; this->vel = vel;
this->acc = acc; this->acc = acc;
this->mass = 1.0; this->mass = 1.0;
turnleft = turnright = moveforward = movebackward = missile = \ turnleft = false;
attractor = firework = false; turnright = false;
moveforward = false;
movebackward = false;
missile = false;
attractor = false;
firework = false;
firedelay = 0.0f; firedelay = 0.0f;
} }
@ -939,8 +985,10 @@ void Botship::Think(float deltatime)
float targetsafety = 0.0f; float targetsafety = 0.0f;
for ( Object* obj = firstobject; !needreturn && obj; obj = obj->NextObj() ) for ( Object* obj = firstobject; !needreturn && obj; obj = obj->NextObj() )
{ {
if ( !obj->GCIsAlive() ) { continue; } if ( !obj->GCIsAlive() )
if ( !obj->IsA("Asteroid") ) { continue; } continue;
if ( !obj->IsA("Asteroid") )
continue;
Asteroid* ast = (Asteroid*) obj; Asteroid* ast = (Asteroid*) obj;
if ( ast->Type() == TYPE_CRYSTAL ) if ( ast->Type() == TYPE_CRYSTAL )
continue; continue;
@ -997,7 +1045,7 @@ void Firework::Think(float deltatime)
const size_t NUM_MISSILES = 8; const size_t NUM_MISSILES = 8;
const Vector velocity = Vector(MISSILE_SPEED, 0); const Vector velocity = Vector(MISSILE_SPEED, 0);
const float offsetangle = RandomAngle(); const float offsetangle = RandomAngle();
const float angle = 2 * PI / NUM_MISSILES; const float angle = 2 * M_PI / NUM_MISSILES;
for ( size_t i = 0; i < NUM_MISSILES; i++ ) for ( size_t i = 0; i < NUM_MISSILES; i++ )
{ {
Vector dir = velocity.Rotate(offsetangle + angle * i); Vector dir = velocity.Rotate(offsetangle + angle * i);
@ -1008,10 +1056,13 @@ void Firework::Think(float deltatime)
} }
for ( Object* obj = firstobject; obj; obj = obj->NextObj() ) for ( Object* obj = firstobject; obj; obj = obj->NextObj() )
{ {
if ( !obj->GCIsAlive() ) { continue; } if ( !obj->GCIsAlive() )
if ( !obj->IsA("Asteroid") ) { continue; } continue;
if ( !obj->IsA("Asteroid") )
continue;
Asteroid* ast = (Asteroid*) obj; Asteroid* ast = (Asteroid*) obj;
if ( !ast->InsideMe(pos) ) { continue; } if ( !ast->InsideMe(pos) )
continue;
// Fireworks taken out by asteroids before explosion. // Fireworks taken out by asteroids before explosion.
GCDie(); GCDie();
} }
@ -1031,7 +1082,8 @@ void GameLogic()
deltatime *= timescale; deltatime *= timescale;
Object* first = firstobject; Object* first = firstobject;
Object* obj; Object* obj;
for ( obj = first; obj; obj = obj->NextObj() ) { obj->GCBirth(); } for ( obj = first; obj; obj = obj->NextObj() )
obj->GCBirth();
bool key_a = pop_is_key_just_down(KBKEY_A); bool key_a = pop_is_key_just_down(KBKEY_A);
bool key_b = pop_is_key_just_down(KBKEY_B); bool key_b = pop_is_key_just_down(KBKEY_B);
bool key_space = pop_is_key_just_down(KBKEY_SPACE); bool key_space = pop_is_key_just_down(KBKEY_SPACE);
@ -1044,24 +1096,28 @@ void GameLogic()
new Botship(RandomAngle(), playership->pos, playership->vel); new Botship(RandomAngle(), playership->pos, playership->vel);
for ( obj = first; obj; obj = obj->NextObj() ) for ( obj = first; obj; obj = obj->NextObj() )
{ {
if ( !obj->GCIsBorn() ) { continue; } if ( !obj->GCIsBorn() )
continue;
obj->PreFrame(); obj->PreFrame();
} }
for ( obj = first; obj; obj = obj->NextObj() ) for ( obj = first; obj; obj = obj->NextObj() )
{ {
if ( !obj->GCIsBorn() ) { continue; } if ( !obj->GCIsBorn() )
continue;
obj->OnFrame(deltatime); obj->OnFrame(deltatime);
} }
for ( obj = first; obj; obj = obj->NextObj() ) for ( obj = first; obj; obj = obj->NextObj() )
{ {
if ( !obj->GCIsBorn() ) { continue; } if ( !obj->GCIsBorn() )
continue;
obj->PostFrame(deltatime); obj->PostFrame(deltatime);
} }
for ( obj = first; obj; ) for ( obj = first; obj; )
{ {
Object* todelete = obj; Object* todelete = obj;
obj = obj->NextObj(); obj = obj->NextObj();
if ( !todelete->GCIsDead() ) { continue; } if ( !todelete->GCIsDead() )
continue;
delete todelete; delete todelete;
} }
} }
@ -1109,23 +1165,6 @@ void RunFrame(struct dispd_window* window)
dispd_finish_render(fb); dispd_finish_render(fb);
} }
char* GetCurrentVideoMode()
{
FILE* fp = fopen("/dev/video/mode", "r");
if ( !fp ) { return NULL; }
char* mode = NULL;
size_t n = 0;
getline(&mode, &n, fp);
fclose(fp);
return mode;
}
int atoi_safe(const char* str)
{
if ( !str ) { return 0; }
return atoi(str);
}
void InitGame() void InitGame()
{ {
clock_gettime(CLOCK_MONOTONIC, &lastframeat); clock_gettime(CLOCK_MONOTONIC, &lastframeat);