sound is so buggy.

This commit is contained in:
Andreas Ortmann 2016-10-03 18:45:24 +02:00
parent becf8602d7
commit 550556e0e4
12 changed files with 303 additions and 160 deletions

View file

@ -6,10 +6,10 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
function(setup_target NAME) function(setup_target NAME)
set_property(TARGET ${NAME} PROPERTY CXX_STANDARD 14) set_property(TARGET ${NAME} PROPERTY CXX_STANDARD 14)
set_property(TARGET ${NAME} PROPERTY CXX_STANDARD_REQUIRED ON) set_property(TARGET ${NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
target_compile_options(${NAME} PRIVATE -Wall -Wextra) #target_compile_options(${NAME} PRIVATE -Wall -Wextra)
target_compile_options(${NAME} PRIVATE -fdiagnostics-color=always) #target_compile_options(${NAME} PRIVATE -fdiagnostics-color=always)
target_compile_options(${NAME} PRIVATE $<$<CONFIG:DEBUG>:-ggdb -O2>) #target_compile_options(${NAME} PRIVATE $<$<CONFIG:DEBUG>:-ggdb -O2>)
target_compile_options(${NAME} PRIVATE $<$<CONFIG:RELEASE>:-O3 -NDEBUG>) #target_compile_options(${NAME} PRIVATE $<$<CONFIG:RELEASE>:-O3 -NDEBUG>)
endfunction(setup_target) endfunction(setup_target)
add_subdirectory(game) add_subdirectory(game)

View file

@ -22,10 +22,6 @@ set(GAME_SRC
util.cpp util.cpp
game.cpp game.cpp
# TODO: make optional!
sound/sound.cpp
sound/sound_effects.cpp
state/object.cpp state/object.cpp
state/explosion.cpp state/explosion.cpp
state/trace.cpp state/trace.cpp
@ -37,6 +33,14 @@ set(GAME_SRC
state/state.cpp state/state.cpp
) )
set(SOUND_LIBRARIES "")
# TODO: make optional!
set(GAME_SRC ${GAME_SRC} sound/sound.cpp sound/sound_effects.cpp)
set(SOUND_LIBRARIES -lportaudio -lsndfile)
#set(GAME_SRC "${GAME_SRC} sound/dummy_sound.cpp sound/dummy_sound_effects.cpp")
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${OPENGL_INCLUDE_DIR}) include_directories(${OPENGL_INCLUDE_DIR})
@ -47,4 +51,4 @@ include_directories(${assimp_INCLUDE_DIRS})
add_executable(game ${GAME_SRC}) add_executable(game ${GAME_SRC})
setup_target(game) setup_target(game)
target_link_libraries(game X11 epoxy pthread ${assimp_LIBRARIES} assimp -lportaudio -lsndfile) target_link_libraries(game X11 epoxy pthread ${assimp_LIBRARIES} assimp ${SOUND_LIBRARIES})

View file

@ -10,7 +10,9 @@
#include "network/server.hpp" #include "network/server.hpp"
#include "options.hpp" #include "options.hpp"
#include "sound/sound.hpp"
#include "sound/sound_effects.hpp" #include "sound/sound_effects.hpp"
#include "state/state_update_event.hpp" #include "state/state_update_event.hpp"
#include <sys/time.h> #include <sys/time.h>
@ -85,11 +87,11 @@ int main(int argc, char *argv[])
srand(time(NULL)); srand(time(NULL));
//sound::SoundEffects *sounds = nullptr; sound::SoundEffects *sounds = nullptr;
if (soundEnabled) { if (soundEnabled) {
//if (sound::initSound()) { if (sound::initSound()) {
//sounds = new sound::SoundEffects(); sounds = new sound::SoundEffects();
//} }
} }
Game game; Game game;
@ -115,9 +117,12 @@ int main(int argc, char *argv[])
// } // }
//} //}
//if (sounds != nullptr) { if (sounds != nullptr) {
// sounds.advance(game->state()); // TODO: get time diff too
//} sounds->advance(1/50.0f, game.state()->currentStateUpdateEvents());
// TODO: use flag to now when to do this.
sound::deleteOldSounds();
}
game.state()->applyAndClearAllOldStateUpdates(); game.state()->applyAndClearAllOldStateUpdates();
} }

View file

@ -101,7 +101,7 @@ namespace endofthejedi {
resize(); resize();
} else if (event.type == ClientMessage) { } else if (event.type == ClientMessage) {
if (event.xclient.data.l[0] == m_atomWmDeleteWindow) { if (event.xclient.data.l[0] == (int) m_atomWmDeleteWindow) {
stop(); stop();
} }
} else if (event.type == DestroyNotify) { } else if (event.type == DestroyNotify) {

View file

@ -14,23 +14,38 @@
// for dumping sound // for dumping sound
#include <sndfile.h> #include <sndfile.h>
#include <pthread.h>
namespace sound { namespace sound {
typedef struct { //struct Slot {
// bool used;
// bool usable;
// bool deleteOnCleanup;
// SoundHandle *handle;
//};
struct SoundContext {
PaStream *stream; PaStream *stream;
// this locks access to the context
pthread_mutex_t mutex;
unsigned int framesPerBuffer; unsigned int framesPerBuffer;
unsigned int sampleRate; unsigned int sampleRate;
unsigned int sound_uid_counter; size_t sound_uid_counter;
// constant // constant
unsigned int maxNumSounds; size_t maxNumSounds;
// num active sonuds // index of highest sound or -1, if there are no sounds.
unsigned int highestSoundIndex; // so 0 means no sounds, > 0 could mean different things depending on
// empty sounds.
volatile ssize_t highestSoundIndex;
// pointer to array of sound handles that has this number of active sounds // pointer to array of sound handles that has this number of active sounds
//Slot *soundSlots;
SoundHandle **sounds; SoundHandle **sounds;
bool dumping; bool dumping;
@ -39,7 +54,7 @@ namespace sound {
SF_INFO sfinfo; SF_INFO sfinfo;
bool init; bool init;
} SoundContext; };
// singleton so no arguments must be supplied for play() functions etc. // singleton so no arguments must be supplied for play() functions etc.
static SoundContext context; static SoundContext context;
@ -83,7 +98,7 @@ namespace sound {
if (handle->envelope != next) { if (handle->envelope != next) {
#if 1 #if 1
printf("[sound] global time %4.3f #%d (%s) t=%f %5s -> %5s\n", printf("[sound] global time %4.3f #%zd (%s) t=%f %5s -> %5s\n",
global_time, global_time,
handle->uid, handle->uid,
handle->name, handle->name,
@ -107,9 +122,9 @@ namespace sound {
context.dumping = false; context.dumping = false;
if (err < 0) { if (err < 0) {
printf("warning: stop dumping wav returned error: %d\n", err); fprintf(stderr, "[sound] warning: stop dumping wav returned error: %d\n", err);
} else { } else {
printf("sucessfully stopped dumping to file %s\n", context.dump_filename); printf("[sound] sucessfully stopped dumping to file %s\n", context.dump_filename);
} }
} }
@ -118,7 +133,7 @@ namespace sound {
// TODO: dumping in mono? // TODO: dumping in mono?
if (!context.init || !context.dumping) { if (!context.init || !context.dumping) {
printf("warning: can't dump samples: context not initialized or not currently dumping!\n"); fprintf(stderr, "[sound] warning: can't dump samples: context not initialized or not currently dumping!\n");
return false; return false;
} }
@ -135,7 +150,7 @@ namespace sound {
} }
if (context.dumping) { if (context.dumping) {
printf("warning: already dumping to %s!\n", context.dump_filename); printf("[sound] warning: already dumping to %s!\n", context.dump_filename);
return false; return false;
} }
@ -146,12 +161,12 @@ namespace sound {
context.outfile = sf_open(filename, SFM_WRITE, &context.sfinfo); context.outfile = sf_open(filename, SFM_WRITE, &context.sfinfo);
if (context.outfile == NULL) { if (context.outfile == NULL) {
printf("Unable to dump to output file %s.\n", filename); fprintf(stderr, "[sound] Unable to dump to output file %s.\n", filename);
sf_perror(NULL); sf_perror(NULL);
return false; return false;
}; };
//printf("start dumping wav to file %s\n", filename); printf("[sound] start dumping wav to file %s\n", filename);
context.dump_filename = filename; context.dump_filename = filename;
context.dumping = true; context.dumping = true;
return true; return true;
@ -277,7 +292,7 @@ namespace sound {
if (n >= handle->numHistorySamples) { if (n >= handle->numHistorySamples) {
// TODO clear history when looping? // TODO clear history when looping?
// or add zero samples? // or add zero samples?
printf("warning: try to access more history values than saved.\n"); printf("[sound] warning: try to access more history values than saved.\n");
return 0.0; return 0.0;
} }
@ -311,6 +326,25 @@ namespace sound {
return result; return result;
} }
// return false on no success
bool tryLock()
{
int ret = pthread_mutex_trylock(&context.mutex);
return ret == 0;
}
// wait if does not lock
void lock()
{
pthread_mutex_lock(&context.mutex);
}
void unlock()
{
pthread_mutex_unlock(&context.mutex);
}
// return false if playing done. // return false if playing done.
static bool advanceSound(SoundHandle *handle, float *out, unsigned int framesPerBuffer) static bool advanceSound(SoundHandle *handle, float *out, unsigned int framesPerBuffer)
{ {
@ -406,7 +440,7 @@ namespace sound {
break; break;
default: default:
printf("warning: unimplemented sound type for #%d: %d\n", handle->uid, handle->_type); printf("[sound] warning: unimplemented sound type for #%zd: %d\n", handle->uid, handle->_type);
continue; continue;
} }
@ -457,23 +491,31 @@ namespace sound {
// we have 32 bit float format so cast here // we have 32 bit float format so cast here
float *out = (float *) outputBuffer; float *out = (float *) outputBuffer;
// set all to zero {
unsigned int i; // set all to zero
for (i=0; i<framesPerBuffer; i++) { unsigned int i;
*out++ = 0.0f; for (i=0; i<framesPerBuffer; i++) {
*out++ = 0.0f; *out++ = 0.0f;
*out++ = 0.0f;
}
} }
// reset pointer // reset pointer
out = (float *) outputBuffer; out = (float *) outputBuffer;
// advance all sounds // advance all sounds
ssize_t i;
for (i=0; i<context.highestSoundIndex; i++) { for (i=0; i<context.highestSoundIndex; i++) {
SoundHandle *handle = context.sounds[i]; SoundHandle *handle = context.sounds[i];
// XXX
if (handle == NULL) { if (handle == NULL) {
continue; continue;
} }
if (handle->deleteFlag) {
continue;
}
if (handle->isDeleted) {
continue;
}
if (!handle->_done) { if (!handle->_done) {
#if 0 #if 0
@ -489,12 +531,14 @@ namespace sound {
} }
// TODO: when we should not free in the loop, where else? // TODO: when we should not free in the loop, where else?
if (handle->_done) { if (handle->_done && !handle->deleteFlag) {
//printf("[sound] %f freeing sound #%d handle 0x%p\n", global_time, handle->uid, handle); //printf("[sound] %f freeing sound #%d handle 0x%p\n", global_time, handle->uid, handle);
context.sounds[i] = NULL; printf("[sound] %f mark sound #%zd handle 0x%p for deletion\n", global_time, handle->uid, handle);
if (!handle->keep_when_done) { //context.sounds[i] = NULL;
deleteSound(handle); handle->deleteFlag = true;
} //if (!handle->keep_when_done) {
// deleteSound(handle);
//}
} }
} }
@ -548,10 +592,11 @@ namespace sound {
// TODO: add max number of simultanous playing sounds, that's more important. // TODO: add max number of simultanous playing sounds, that's more important.
context.sound_uid_counter = 0; context.sound_uid_counter = 0;
context.maxNumSounds = 50; context.maxNumSounds = 10;
context.highestSoundIndex = 0; context.highestSoundIndex = -1;
//context.soundSlots = (Slot*) calloc(context.maxNumSounds, 1000); // XXX HACK
context.sounds = (SoundHandle **) calloc(context.maxNumSounds, 1000); // XXX HACK context.sounds = (SoundHandle **) calloc(context.maxNumSounds, 1000); // XXX HACK
assert(context.sounds != NULL); //assert(context.soundSlots != NULL);
PaError err = Pa_Initialize(); PaError err = Pa_Initialize();
if (err != paNoError) { if (err != paNoError) {
@ -647,21 +692,39 @@ namespace sound {
return NULL; return NULL;
} }
size_t nextFreeIndex = 0; ssize_t nextFreeIndex = 0;
while(nextFreeIndex < context.highestSoundIndex) { while(nextFreeIndex <= context.highestSoundIndex) {
if (context.sounds[nextFreeIndex] == NULL) { if (context.sounds[nextFreeIndex] == NULL || context.sounds[nextFreeIndex]->isDeleted) {
// got an empyt sound to use // got an empty sound to use
break; break;
} }
nextFreeIndex++; nextFreeIndex++;
} }
if (nextFreeIndex >= context.maxNumSounds) { if (context.sounds[nextFreeIndex] != NULL) {
printf("error: can't create more sounds, got maximum of: %d\n", context.maxNumSounds); printf("[sound] playSound() finally free'ing old sound: %zd\n",
context.sounds[nextFreeIndex]->uid);
free(context.sounds[nextFreeIndex]);
context.sounds[nextFreeIndex] = NULL;
}
if (context.sounds[nextFreeIndex] != NULL) {
fprintf(stderr, "[sound] warning: playSound() nextFreeIndex is "
"%zd but that sound is not NULL!\n", nextFreeIndex);
return NULL;
}
if (nextFreeIndex+1 >= (ssize_t) context.maxNumSounds) {
printf("[sound] warning: can't create more sounds, got maximum of: %zd\n", context.maxNumSounds);
return NULL; return NULL;
} }
SoundHandle *handle = (SoundHandle *) calloc(1, sizeof(SoundHandle)); SoundHandle *handle = (SoundHandle *) calloc(1, sizeof(SoundHandle));
handle->deleteFlag = false;
handle->isDeleted = false;
handle->_done = false;
handle->envelope = New; handle->envelope = New;
handle->amplitude = amplitude; handle->amplitude = amplitude;
handle->minAmplitude = 0.0; handle->minAmplitude = 0.0;
@ -674,7 +737,6 @@ namespace sound {
handle->state = 0.0; handle->state = 0.0;
handle->leakage = 0.0; handle->leakage = 0.0;
handle->scaling = 0.0; handle->scaling = 0.0;
handle->_done = false;
handle->skipDirectionIfClamping = false; handle->skipDirectionIfClamping = false;
handle->_useEnvelope = false; handle->_useEnvelope = false;
@ -725,9 +787,16 @@ namespace sound {
context.sounds[nextFreeIndex] = handle; context.sounds[nextFreeIndex] = handle;
if (nextFreeIndex == context.highestSoundIndex) { if (nextFreeIndex == context.highestSoundIndex+1) {
context.highestSoundIndex++; context.highestSoundIndex++;
} }
//if (nextFreeIndex < context.highestSoundIndex) {
// fprintf(stderr, "[sound] warning: nextFreeIndex > context.highestSoundIndex, "
// "this should not happen: %zd %zd\n", nextFreeIndex, context.highestSoundIndex);
//}
printf("[sound] playSound() created sound #%zd name %s\n", handle->uid, handle->name);
printf("[sound] highestSoundIndex now %zd\n", context.highestSoundIndex);
return handle; return handle;
} }
@ -917,8 +986,9 @@ namespace sound {
int numActiveSounds(void) int numActiveSounds(void)
{ {
int num = 0; int num = 0;
size_t i; ssize_t i;
for (i=0; i<context.highestSoundIndex; i++) { for (i=0; i<=context.highestSoundIndex; i++) {
// TODO: active is when not done or not deleted!
if (context.sounds[i] != NULL) { if (context.sounds[i] != NULL) {
num++; num++;
} }
@ -932,12 +1002,12 @@ namespace sound {
return; return;
} }
// just for sure // just to be sure
handle->_done = true; handle->_done = true;
// clear from that // clear from that
size_t i; ssize_t i;
for (i=0; i<context.highestSoundIndex; i++) { for (i=0; i<=context.highestSoundIndex; i++) {
if (context.sounds[i] == handle) { if (context.sounds[i] == handle) {
context.sounds[i] = NULL; context.sounds[i] = NULL;
if (i+1 == context.highestSoundIndex) { if (i+1 == context.highestSoundIndex) {
@ -965,4 +1035,37 @@ namespace sound {
return false; return false;
} }
} }
void deleteOldSounds(void)
{
ssize_t i;
for (i=0; i<=context.highestSoundIndex; i++) {
SoundHandle *handle = context.sounds[i];
if (handle != NULL && handle->deleteFlag) {
//context.sounds[i] = NULL;
printf("[sound] %f finally deleting sound #%zd handle 0x%p\n", global_time, handle->uid, handle);
if (handle->history != NULL) {
free(handle->history);
}
handle->isDeleted = true;
handle->deleteFlag = false;
//free(handle);
}
}
ssize_t nextHighestSoundIndex = -1;
for (i=0; i<=context.highestSoundIndex; i++) {
SoundHandle *handle = context.sounds[i];
if (handle != NULL) {
nextHighestSoundIndex = i;
}
}
if (context.highestSoundIndex != nextHighestSoundIndex) {
printf("[sound] deleteOldSounds() setting hightest sound index from %zd to %zd\n",
context.highestSoundIndex, nextHighestSoundIndex);
context.highestSoundIndex = nextHighestSoundIndex;
}
}
} }

View file

@ -31,12 +31,19 @@ namespace sound {
SoundDecayExp = 1 SoundDecayExp = 1
}; };
typedef struct { struct SoundHandle {
// just for debugging/logging. don't rely on use // just for debugging/logging. don't rely on use
const char *name; const char *name;
// unique ID for accessing them via lookups etc. if sound is dead, this will be never reused // unique ID for accessing them via lookups etc. if sound is dead, this will be never reused
int uid; size_t uid;
// marked for deletion by the internal thread.
bool deleteFlag;
// is now deleted. when a new sound should be used, this can be reused
// and at the end deleteFlag and isDeleted should be cleared.
bool isDeleted;
// if true, don't deallocate once this is done. // if true, don't deallocate once this is done.
bool keep_when_done; bool keep_when_done;
@ -110,11 +117,15 @@ namespace sound {
float *history; // if != 0, history is a pointer to 2*numHistorySamples samples. float *history; // if != 0, history is a pointer to 2*numHistorySamples samples.
size_t numHistorySamples; // if != 0, save history for this sound. size_t numHistorySamples; // if != 0, save history for this sound.
size_t lastHistorySample; // index/2 of last history sample. used size_t lastHistorySample; // index/2 of last history sample. used
} SoundHandle; };
// initialize sound subsystem. return true if working, false on errors. // initialize sound subsystem. return true if working, false on errors.
bool initSound(void); bool initSound(void);
// free sounds that are not used anymore.
// must be called regularily by the application
void deleteOldSounds();
// start playing a sound. // start playing a sound.
// args: // args:
// type - type of sound. // type - type of sound.

View file

@ -2,76 +2,82 @@
#include "sound.hpp" #include "sound.hpp"
#include "util.hpp"
namespace sound { namespace sound {
#if 0 void SoundEffects::addSoundHandleForObject(game::Object *obj, SoundHandle *handle)
class MissileFlySoundEffect : public SoundEffect { {
MissileFlySoundEffect(const game::Missile *missile) std::cout<<"add sound for object: " << obj->id << std::endl;
: m_missileId(missile->id) auto pair = std::pair<size_t, SoundHandle*>(obj->id, handle);
, m_handle(sound::playSound(sound::playFrequency(440, 0.3)) m_mapObjectToSoundHandle.insert(pair);
{ }
void SoundEffects::fadeOutSoundHandlesForObject(game::Object *obj, float fadeOutTime)
{
std::cout<<"deleting sounds for object: " << obj->id << std::endl;
std::multimap<size_t, SoundHandle*>::iterator it;
for (it = m_mapObjectToSoundHandle.find(obj->id); it != m_mapObjectToSoundHandle.end(); it++) {
std::cout<<"sound #" << it->second->uid << " / " << it->second->name << std::endl;
fadeOut(it->second, fadeOutTime);
} }
~MissileFlySoundEffect() size_t numRemoved = m_mapObjectToSoundHandle.erase(obj->id);
{ std::cout<<"removed total sounds: " << numRemoved << std::endl;
delete(m_handle); }
}
bool advance(float dt)
{
for (const game::StateUpdateEvent *event : updates) {
handleUpdateEvent(event);
}
// TODO: add event if sth. comes into life or dies in a state
// cycle.. delete objects that died last cycle in the current cycle
// so pointers don't get invalid.
bool keep = false;
for (const game::Missile *missile : state->missiles) {
if (missile->id == m_missileId) {
keep = true;
break;
}
}
if (!keep) {
sound::stopSound(m_handle);
sound::deleteSound(m_handle);
return false;
}
return true;
}
private:
SoundHandle *m_handle;
size_t m_missileId;
};
void SoundEffects::advance(float dt, const std::list<game::StateUpdateEvent*> &updates) void SoundEffects::advance(float dt, const std::list<game::StateUpdateEvent*> &updates)
{ {
//StateUpdateEvent::LifeCycle::Create, (void) dt;
//StateUpdateEvent::Type::Explosion
std::vector<SoundEffect*> rm; for (const game::StateUpdateEvent *evt : updates) {
auto type = evt->eventType();
auto cycle = evt->lifeCycle();
if (type == game::EventType::Missile) {
if (cycle == game::LifeCycle::Create) {
SoundHandle *handle = playFrequency(880.0, 0.1);
if (handle == nullptr) {
continue;
}
fadeIn(handle);
handle->name = "missile-fly-sound_fade-in";
for (SoundEffect *effect : m_effects) { addSoundHandleForObject(evt->object(), handle);
bool keep = effect->advance(dt, m_gameState);
if (!keep) { } else if (cycle == game::LifeCycle::Destroy) {
rm.push_back(effect); fadeOutSoundHandlesForObject(evt->object());
}
} else if (type == game::EventType::Explosion) {
#if 1
if (cycle == game::LifeCycle::Create) {
SoundHandle *handle = playSound(SoundBrownianNoise, 0.4);
if (handle == nullptr) {
continue;
}
configureEnvelope(handle, 0.2, 0.0, 2.0);
// add big *boom* sound too
handle = playFrequency(200.0, 0.5);
if (handle == nullptr) {
continue;
}
configureEnvelope(handle, 0.1, 0.0, 1.0);
}
#endif
} }
} }
for (SoundEffect *effect : rm) {
m_effects.remove(rm);
delete(rm);
}
// spawn new sounds
//for (const game::Missile *missile : state->missiles) {
// for (SoundEffect
// if (missile->
//}
} }
#endif
void SoundEffects::fadeIn(SoundHandle *handle, float fadeInTime)
{
// assume sound has just started
configureEnvelope(handle, fadeInTime, 1000000.0, 0.0);
}
void SoundEffects::fadeOut(SoundHandle *handle, float fadeOutTime)
{
// reset time so it imediately starts to fade out.
configureEnvelope(handle, 0.0, 0.0, fadeOutTime);
handle->time = 0.0;
}
} }

View file

@ -1,15 +1,14 @@
#pragma once #pragma once
#include <list> #include <list>
#include <map>
#include "state/state.hpp" #include "state/state.hpp"
namespace sound { namespace sound {
#if 0 struct SoundHandle;
namespace game {
class StateUpdateEvent;
}
#if 0
class SoundEffect { class SoundEffect {
public: public:
virtual ~SoundEffects() virtual ~SoundEffects()
@ -19,6 +18,7 @@ namespace sound {
// return false if it can be deleted // return false if it can be deleted
virtual bool advance(float dt) = 0; virtual bool advance(float dt) = 0;
}; };
#endif
class SoundEffects { class SoundEffects {
public: public:
@ -26,11 +26,18 @@ namespace sound {
{ {
} }
void handleUpdateEvent(game::StateUpdateEvent *event);
void advance(float dt, const std::list<game::StateUpdateEvent*> &updates); void advance(float dt, const std::list<game::StateUpdateEvent*> &updates);
private: private:
std::list<SoundEffect*> m_effects; void fadeIn(SoundHandle *handle, float fadeInTime=0.3f);
} void fadeOut(SoundHandle *handle, float fadeOutTime=0.3f);
#endif
void addSoundHandleForObject(game::Object *obj, SoundHandle *handle);
void fadeOutSoundHandlesForObject(game::Object *obj, float fadeOutTime=0.3f);
private:
std::list<SoundHandle*> m_soundHandles;
std::multimap<size_t, SoundHandle*> m_mapObjectToSoundHandle;
//std::list<SoundEffect*> m_effects;
};
} }

View file

@ -14,7 +14,7 @@ namespace game {
// angles are supplied in degrees and are CCW // angles are supplied in degrees and are CCW
Missile *missile = new Missile( Missile *missile = new Missile(
state->generateMissileId(), state->generateId(),
player, player,
player->ship->position, player->ship->position,
-util::deg2rad(m_angle), -util::deg2rad(m_angle),
@ -30,7 +30,8 @@ namespace game {
{ {
(void) state; (void) state;
return player->alive && player->energy >= player->speed; //return player->alive && player->energy >= player->speed;
return player->alive;
} }
void ChangeNameCommand::apply(Player *player, State *state) const void ChangeNameCommand::apply(Player *player, State *state) const
@ -76,6 +77,8 @@ namespace game {
void DeveloperCommand::apply(Player *player, State *state) const void DeveloperCommand::apply(Player *player, State *state) const
{ {
(void) player;
if (!state->developerMode()) { if (!state->developerMode()) {
std::cout<<"ignoring dev command while not in developer mode: '" std::cout<<"ignoring dev command while not in developer mode: '"
<< m_payload << "'" << std::endl; << m_payload << "'" << std::endl;
@ -96,6 +99,7 @@ namespace game {
void SetDeveloperModeCommand::apply(Player *player, State *state) const void SetDeveloperModeCommand::apply(Player *player, State *state) const
{ {
(void) player;
// TODO: check if player is admin // TODO: check if player is admin
state->setDeveloperMode(m_enable); state->setDeveloperMode(m_enable);

View file

@ -32,9 +32,6 @@ namespace game {
// TODO: clear shots etc. too // TODO: clear shots etc. too
m_nextPlayerId = 0;
m_nextMissileId = 0;
m_nextShipId = 0;
m_time = 0.0; m_time = 0.0;
m_shipRadius = 0.02; m_shipRadius = 0.02;
m_maxMissileDistance = 2.0; m_maxMissileDistance = 2.0;
@ -42,7 +39,6 @@ namespace game {
m_defaultEnergy = 10.0; m_defaultEnergy = 10.0;
m_maxNumTraces = 10; m_maxNumTraces = 10;
m_developerMode = devMode; m_developerMode = devMode;
m_nextExplosionId = 0;
setPlayingFieldCenter(0, 0); setPlayingFieldCenter(0, 0);
@ -144,7 +140,7 @@ namespace game {
return false; return false;
} }
Ship *ship = new Ship(m_nextShipId++, spawnPos, m_shipRadius); Ship *ship = new Ship(generateId(), spawnPos, m_shipRadius);
player->ship = ship; player->ship = ship;
ships.push_back(ship); ships.push_back(ship);
@ -157,7 +153,7 @@ namespace game {
size_t State::addPlayer() size_t State::addPlayer()
{ {
Player *player = new Player(m_nextPlayerId++); Player *player = new Player(generateId());
players.push_back(player); players.push_back(player);
return player->id; return player->id;
} }
@ -483,7 +479,7 @@ namespace game {
} }
Explosion *explosion = new Explosion( Explosion *explosion = new Explosion(
m_nextExplosionId++, evt->position, generateId(), evt->position,
evt->missileVelocity, evt->hit); evt->missileVelocity, evt->hit);
explosions.push_back(explosion); explosions.push_back(explosion);
@ -519,9 +515,9 @@ namespace game {
m_playingFieldSize = glm::vec2(width, height); m_playingFieldSize = glm::vec2(width, height);
} }
size_t State::generateMissileId() size_t State::generateId()
{ {
return m_nextMissileId++; return m_ids.makeNextId();
} }
void State::applyAndClearAllOldStateUpdates() void State::applyAndClearAllOldStateUpdates()
@ -532,8 +528,8 @@ namespace game {
case EventType::Explosion: case EventType::Explosion:
{ {
ExplosionEvent *ee = static_cast<ExplosionEvent*>(evt); ExplosionEvent *ee = static_cast<ExplosionEvent*>(evt);
//std::cout<<"got explosion delete event, finally deleting explosion #" std::cout<<"got explosion delete event, finally deleting explosion #"
// << ee->explosion->id << std::endl; << ee->object()->id << std::endl;
delete(ee->object()); delete(ee->object());
} }
@ -542,8 +538,8 @@ namespace game {
case EventType::Missile: case EventType::Missile:
{ {
auto *me = static_cast<MissileEvent*>(evt); auto *me = static_cast<MissileEvent*>(evt);
//std::cout<<"got missile delete event, finally deleting missile #" std::cout<<"got missile delete event, finally deleting missile #"
// << me->missile->id << std::endl; << me->object()->id << std::endl;
delete(me->object()); delete(me->object());
} }

View file

@ -35,6 +35,25 @@ namespace game {
class Trace; class Trace;
class Explosion; class Explosion;
class IdGenerator {
public:
IdGenerator() : m_nextId(0)
{
}
size_t makeNextId()
{
return m_nextId++;
if (m_nextId == 0) {
std::cerr << "note: id counter just wrapped to 0, "
"funny things can happen now." << std::endl;
}
}
private:
size_t m_nextId;
};
class State { class State {
public: public:
/*************************************************************************/ /*************************************************************************/
@ -105,7 +124,7 @@ namespace game {
void setPlayingFieldSize(int width, int height); void setPlayingFieldSize(int width, int height);
void setPlayingFieldCenter(int width, int height); void setPlayingFieldCenter(int width, int height);
size_t generateMissileId(); size_t generateId();
void applyAndClearAllOldStateUpdates(); void applyAndClearAllOldStateUpdates();
@ -159,10 +178,7 @@ namespace game {
float m_shipRadius; float m_shipRadius;
float m_defaultEnergy; float m_defaultEnergy;
int m_maxNumTraces; int m_maxNumTraces;
size_t m_nextPlayerId; IdGenerator m_ids;
size_t m_nextExplosionId;
size_t m_nextMissileId;
size_t m_nextShipId;
float m_time; float m_time;
bool m_developerMode; bool m_developerMode;

View file

@ -1,9 +0,0 @@
#!/usr/bin/env python3
import os
import random
for i in range(100):
a = random.randint(0, 360)
print("spawn #%d +shoot %d" % (i, a))
os.system("echo %d | ncat 192.168.0.191 3490" % a)