Switched scene update to state event

This commit is contained in:
2023-03-01 09:40:57 -08:00
parent 6aa7d317d1
commit 1061cda666
10 changed files with 438 additions and 473 deletions

View File

@ -36,8 +36,8 @@ void Scene::update() {
// TODO: Cleanup old scene items // TODO: Cleanup old scene items
// TODO: Tick scene items(?) // TODO: Tick scene items(?)
this->eventSceneUpdate.invoke(); this->eventSceneUpdate.invoke(game->timeManager.delta);
if(!this->game->timeManager.isPaused) this->eventSceneUnpausedUpdate.invoke(); if(!this->game->timeManager.isPaused) this->eventSceneUnpausedUpdate.invoke(game->timeManager.delta);
} }
SceneItem * Scene::createSceneItem() { SceneItem * Scene::createSceneItem() {

View File

@ -21,7 +21,7 @@ namespace Dawn {
template<class T> template<class T>
T * _sceneForwardGetComponent(SceneItem *item); T * _sceneForwardGetComponent(SceneItem *item);
class Scene : public StateOwner { class Scene {
private: private:
sceneitemid_t nextId; sceneitemid_t nextId;
std::map<sceneitemid_t, SceneItem*> items; std::map<sceneitemid_t, SceneItem*> items;
@ -30,8 +30,8 @@ namespace Dawn {
public: public:
DawnGame *game; DawnGame *game;
ScenePhysicsManager *physics; ScenePhysicsManager *physics;
Event<> eventSceneUpdate; StateEvent<float_t> eventSceneUpdate;
Event<> eventSceneUnpausedUpdate; StateEvent<float_t> eventSceneUnpausedUpdate;
/** /**
* Construct a new Scene instance. * Construct a new Scene instance.

View File

@ -22,10 +22,10 @@ void AnimationController::addAnimation(Animation *animation) {
void AnimationController::onStart() { void AnimationController::onStart() {
SceneItemComponent::onStart(); SceneItemComponent::onStart();
useEventLegacy([&]{ useEvent([&](float_t delta){
auto it = this->animations.begin(); auto it = this->animations.begin();
while(it != this->animations.end()) { while(it != this->animations.end()) {
(*it)->tick(this->getGame()->timeManager.delta); (*it)->tick(delta);
++it; ++it;
} }
}, getScene()->eventSceneUnpausedUpdate); }, getScene()->eventSceneUnpausedUpdate);

View File

@ -28,11 +28,11 @@ ExampleSpin::ExampleSpin(SceneItem *item) :
} }
void ExampleSpin::onStart() { void ExampleSpin::onStart() {
useEventLegacy([&]{ useEvent([&](float_t delta){
auto quat = this->transform->getLocalRotation(); auto quat = this->transform->getLocalRotation();
quat = glm::rotate(quat, getGame()->timeManager.delta, glm::vec3(0, 1, 0)); quat = glm::rotate(quat, delta, glm::vec3(0, 1, 0));
quat = glm::rotate(quat, getGame()->timeManager.delta / 2.0f, glm::vec3(1, 0, 0)); quat = glm::rotate(quat, delta / 2.0f, glm::vec3(1, 0, 0));
quat = glm::rotate(quat, getGame()->timeManager.delta / 4.0f, glm::vec3(0, 0, 1)); quat = glm::rotate(quat, delta / 4.0f, glm::vec3(0, 0, 1));
this->transform->setLocalRotation(quat); this->transform->setLocalRotation(quat);
}, getScene()->eventSceneUnpausedUpdate); }, getScene()->eventSceneUnpausedUpdate);
} }

View File

@ -14,13 +14,13 @@ SubSceneController::SubSceneController(SceneItem *i) : SceneItemComponent(i) {
void SubSceneController::onStart() { void SubSceneController::onStart() {
auto myScene = this->getScene(); auto myScene = this->getScene();
useEventLegacy([&]{ useEvent([&](float_t d){
if(!this->onlyUpdateUnpaused) return; if(!this->onlyUpdateUnpaused) return;
if(this->subScene == nullptr) return; if(this->subScene == nullptr) return;
this->subScene->update(); this->subScene->update();
}, myScene->eventSceneUnpausedUpdate); }, myScene->eventSceneUnpausedUpdate);
useEventLegacy([&]{ useEvent([&](float_t d){
if(this->onlyUpdateUnpaused) return; if(this->onlyUpdateUnpaused) return;
if(this->subScene == nullptr) return; if(this->subScene == nullptr) return;
this->subScene->update(); this->subScene->update();

View File

@ -67,7 +67,7 @@ void UICanvas::onStart() {
}, this->currentMenu); }, this->currentMenu);
// Scene Update // Scene Update
useEventLegacy([&]{ useEvent([&](float_t delta){
if(this->currentMenu == nullptr) return; if(this->currentMenu == nullptr) return;
this->currentMenu->onTick(); this->currentMenu->onTick();
}, getScene()->eventSceneUpdate); }, getScene()->eventSceneUpdate);

View File

@ -1,268 +1,257 @@
// Copyright (c) 2023 Dominic Masters // Copyright (c) 2023 Dominic Masters
// //
// This software is released under the MIT License. // This software is released under the MIT License.
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#include "AudioSource.hpp" #include "AudioSource.hpp"
#include "game/DawnGame.hpp" #include "game/DawnGame.hpp"
using namespace Dawn; using namespace Dawn;
AudioSource::AudioSource(SceneItem *i) : SceneItemComponent(i) { AudioSource::AudioSource(SceneItem *i) :
SceneItemComponent(i),
} playMode(AUDIO_PLAY_MODE_UNPAUSED)
{
void AudioSource::fillBuffer(ALuint buffer) { }
// Read in some data
uint8_t *temporaryBuffer = (uint8_t*)memoryAllocate(AUDIO_SOURCE_BUFFER_SIZE);
/* void AudioSource::fillBuffer(ALuint buffer) {
OK A big writeup here because things get complicated and I am sure that I // Read in some data
will need to revist this. uint8_t *temporaryBuffer = (uint8_t*)memoryAllocate(AUDIO_SOURCE_BUFFER_SIZE);
/*
First thing to note is that OpenAL requires that the data buffered is a OK A big writeup here because things get complicated and I am sure that I
multiple of the frame size. Frame Size from what I can tell is; will need to revist this.
dataSize * channelCount
e.g. sizeof(int16_t) * stereo = 4 First thing to note is that OpenAL requires that the data buffered is a
multiple of the frame size. Frame Size from what I can tell is;
EDIT 23017 - Something about how OpenAL handles things means the following dataSize * channelCount
statement is probably false, I'm leaving it here but DON'T READ IT PLEASE e.g. sizeof(int16_t) * stereo = 4
Additionally, we need to handle cases where the buffer "wraps around". So EDIT 23017 - Something about how OpenAL handles things means the following
let's say we are at 8179/8192 bytes, we go to read "128 bytes", we need to statement is probably false, I'm leaving it here but DON'T READ IT PLEASE
first read the remaining 13 bytes and then the remaining (128-13)bytes.
Additionally, we need to handle cases where the buffer "wraps around". So
After that we need to do our frame size division, and make sure we only let's say we are at 8179/8192 bytes, we go to read "128 bytes", we need to
advance our buffer by that many bytes, so that the next buffer can pick up first read the remaining 13 bytes and then the remaining (128-13)bytes.
exactly where this buffer left off.
*/ After that we need to do our frame size division, and make sure we only
advance our buffer by that many bytes, so that the next buffer can pick up
// Try to read the entire buffer exactly where this buffer left off.
this->data->loader.setPosition(this->data->bufferStart + bufferPosition); */
size_t readLength = this->data->loader.read(
temporaryBuffer, AUDIO_SOURCE_BUFFER_SIZE // Try to read the entire buffer
); this->data->loader.setPosition(this->data->bufferStart + bufferPosition);
size_t readLength = this->data->loader.read(
size_t bufferLength = (readLength / this->data->frameSize) * this->data->frameSize; temporaryBuffer, AUDIO_SOURCE_BUFFER_SIZE
);
// Did we run out of data?
size_t newPosition; size_t bufferLength = (readLength / this->data->frameSize) * this->data->frameSize;
if(readLength < AUDIO_SOURCE_BUFFER_SIZE) {
newPosition = 0; // Did we run out of data?
} else { size_t newPosition;
newPosition = bufferPosition + bufferLength; if(readLength < AUDIO_SOURCE_BUFFER_SIZE) {
} newPosition = 0;
} else {
// Determine format, may do this somewhere else for efficiency sake. newPosition = bufferPosition + bufferLength;
ALenum format; }
switch(this->data->channelCount) {
case 2: // Determine format, may do this somewhere else for efficiency sake.
format = AL_FORMAT_STEREO16; ALenum format;
break; switch(this->data->channelCount) {
case 1: case 2:
format = AL_FORMAT_MONO16; format = AL_FORMAT_STEREO16;
break; break;
default: case 1:
assertUnreachable(); format = AL_FORMAT_MONO16;
} break;
default:
// Buffer data assertUnreachable();
alBufferData( }
buffer, format, temporaryBuffer, bufferLength, (ALsizei)this->data->sampleRate
); // Buffer data
alBufferData(
// Cleanup buffer, format, temporaryBuffer, bufferLength, (ALsizei)this->data->sampleRate
memoryFree(temporaryBuffer); );
bufferPosition = newPosition;
} // Cleanup
memoryFree(temporaryBuffer);
void AudioSource::detatchBuffers() { bufferPosition = newPosition;
ALint buffersQueued; }
ALuint buffersUnqueued[AUDIO_SOURCE_BUFFER_COUNT];
alGetSourcei(this->source, AL_BUFFERS_QUEUED, &buffersQueued); void AudioSource::detatchBuffers() {
if(buffersQueued > 0) { ALint buffersQueued;
alSourceUnqueueBuffers(this->source, buffersQueued, buffersUnqueued); ALuint buffersUnqueued[AUDIO_SOURCE_BUFFER_COUNT];
} alGetSourcei(this->source, AL_BUFFERS_QUEUED, &buffersQueued);
} if(buffersQueued > 0) {
alSourceUnqueueBuffers(this->source, buffersQueued, buffersUnqueued);
void AudioSource::attachBuffers() { }
alSourceQueueBuffers(this->source, AUDIO_SOURCE_BUFFER_COUNT, this->buffers); }
}
void AudioSource::attachBuffers() {
void AudioSource::onStart() { alSourceQueueBuffers(this->source, AUDIO_SOURCE_BUFFER_COUNT, this->buffers);
// Create source and buffers }
alGenSources((ALuint)1, &this->source);
alGenBuffers((ALuint)AUDIO_SOURCE_BUFFER_COUNT, this->buffers); void AudioSource::onStart() {
// Create source and buffers
// Set up the source positions alGenSources((ALuint)1, &this->source);
glm::vec3 position = this->transform->getWorldPosition(); alGenBuffers((ALuint)AUDIO_SOURCE_BUFFER_COUNT, this->buffers);
alSource3f(this->source, AL_POSITION, position.x, position.y, position.z);
alSource3f(this->source, AL_VELOCITY, 0, 0, 0); // Set up the source positions
glm::vec3 position = this->transform->getWorldPosition();
// In future these will probably be tied to the layer alSource3f(this->source, AL_POSITION, position.x, position.y, position.z);
alSourcef(this->source, AL_PITCH, 1); alSource3f(this->source, AL_VELOCITY, 0, 0, 0);
alSourcef(this->source, AL_GAIN, 1);
// In future these will probably be tied to the layer
// Mark as ready. alSourcef(this->source, AL_PITCH, 1);
this->ready = true; alSourcef(this->source, AL_GAIN, 1);
// Listen for events // Mark as ready.
this->transform->eventTransformUpdated.addListener(this, &AudioSource::onTransformUpdate); this->ready = true;
this->getScene()->eventSceneUpdate.addListener(this, &AudioSource::onSceneUpdate);
} // Listen for events
useEventLegacy([&]{
AudioSourceState AudioSource::getRealState() { glm::vec3 position = this->transform->getWorldPosition();
return this->internalState; alSource3f(this->source, AL_POSITION, position.x, position.y, position.z);
} }, this->transform->eventTransformUpdated);
void AudioSource::rewind() { useEvent([&](float_t delta){
this->bufferPosition = 0; ALuint bufferId;
} ALint buffersProcessed;
AudioAsset * AudioSource::getAudioData() { assertTrue(this->ready);
return this->data;
} // What is the user trying to do?
if(this->state == AUDIO_SOURCE_STATE_PLAYING) {
void AudioSource::setAudioData(AudioAsset *data) { assertTrue(this->data != nullptr);
this->data = data; assertTrue(this->data->loaded);
this->rewind();
} // Handle the special game-paused music-paused state.
if(this->playMode == AUDIO_PLAY_MODE_UNPAUSED && this->getGame()->timeManager.isPaused) {
enum AudioSourcePlayMode AudioSource::getPlayMode() { if(this->internalState == AUDIO_SOURCE_STATE_PLAYING) {
return this->playMode; // Functionally, this is the same as pausing
} alSourcePause(this->source);
this->internalState = AUDIO_SOURCE_STATE_PAUSED;
void AudioSource::setPlayMode(enum AudioSourcePlayMode playMode) { }
this->playMode = playMode; return;// Do nothing else, at all.
} }
void AudioSource::stop() { // They are trying to play. We need to check if we are already playing
this->state = AUDIO_SOURCE_STATE_STOPPED; if(this->internalState == AUDIO_SOURCE_STATE_PLAYING) {
} // We are good to continue buffering audio data.
buffersProcessed = 0;
void AudioSource::play() { alGetSourcei(this->source, AL_BUFFERS_PROCESSED, &buffersProcessed);
this->state = AUDIO_SOURCE_STATE_PLAYING;
} while(buffersProcessed > 0) {
alSourceUnqueueBuffers(this->source, 1, &bufferId);
void AudioSource::pause() { this->fillBuffer(bufferId);
this->state = AUDIO_SOURCE_STATE_PAUSED; alSourceQueueBuffers(this->source, 1, &bufferId);
} buffersProcessed--;
void AudioSource::onDispose() { // Now, before we go to the next buffer let's see if we need to
assertTrue(this->ready); // update the internal state
this->ready = false; if(this->bufferPosition != 0) continue;
this->getScene()->eventSceneUpdate.removeListener(this, &AudioSource::onSceneUpdate); // We reached the end of the buffer whilst filling. What to do now?
this->transform->eventTransformUpdated.removeListener(this, &AudioSource::onTransformUpdate); if(this->loop) {
// We're looping so it's fine
alDeleteSources((ALuint)1, &this->source); this->eventLooped.invoke();
alDeleteBuffers((ALuint)AUDIO_SOURCE_BUFFER_COUNT, this->buffers); continue;
} }
void AudioSource::onSceneUpdate() { // We are NOT looping, so we need to finish here.
ALuint bufferId; this->state = AUDIO_SOURCE_STATE_STOPPED;
ALint buffersProcessed; this->eventFinished.invoke();
this->bufferPosition = 0;
assertTrue(this->ready); buffersProcessed = 0;
}
// What is the user trying to do? } else if(this->internalState == AUDIO_SOURCE_STATE_STOPPED) {
if(this->state == AUDIO_SOURCE_STATE_PLAYING) { // Not yet playing. First thing we need to do is fill the buffers.
assertTrue(this->data != nullptr); for(int32_t i = 0; i < AUDIO_SOURCE_BUFFER_COUNT; i++) {
assertTrue(this->data->loaded); this->fillBuffer(this->buffers[i]);
}
// Handle the special game-paused music-paused state.
if(this->playMode == AUDIO_PLAY_MODE_UNPAUSED && this->getGame()->timeManager.isPaused) { // Now attach the buffers
if(this->internalState == AUDIO_SOURCE_STATE_PLAYING) { this->attachBuffers();
// Functionally, this is the same as pausing
alSourcePause(this->source); // And begin playing
this->internalState = AUDIO_SOURCE_STATE_PAUSED; alSourcePlay(this->source);
} this->internalState = AUDIO_SOURCE_STATE_PLAYING;
return;// Do nothing else, at all. this->eventPlaying.invoke();
}
} else if(AUDIO_SOURCE_STATE_PAUSED) {
// They are trying to play. We need to check if we are already playing // Request to resume
if(this->internalState == AUDIO_SOURCE_STATE_PLAYING) { alSourcePlay(this->source);
// We are good to continue buffering audio data. this->eventResumed.invoke();
buffersProcessed = 0; this->internalState = AUDIO_SOURCE_STATE_PLAYING;
alGetSourcei(this->source, AL_BUFFERS_PROCESSED, &buffersProcessed);
} else {
while(buffersProcessed > 0) { assertUnreachable();
alSourceUnqueueBuffers(this->source, 1, &bufferId); }
this->fillBuffer(bufferId); } else if(this->state == AUDIO_SOURCE_STATE_PAUSED) {
alSourceQueueBuffers(this->source, 1, &bufferId); assertTrue(this->data != nullptr);
buffersProcessed--; assertTrue(this->data->loaded);
// Now, before we go to the next buffer let's see if we need to // Pause has been requested.
// update the internal state if(this->internalState != AUDIO_SOURCE_STATE_PLAYING) return;
if(this->bufferPosition != 0) continue;
// We are playing something, pause it
// We reached the end of the buffer whilst filling. What to do now? alSourcePause(this->source);
if(this->loop) { this->internalState = AUDIO_SOURCE_STATE_PAUSED;
// We're looping so it's fine this->eventPaused.invoke();
this->eventLooped.invoke();
continue; } else if(this->state == AUDIO_SOURCE_STATE_STOPPED) {
} if(this->internalState == AUDIO_SOURCE_STATE_STOPPED) return;
// We are NOT looping, so we need to finish here. assertTrue(this->data != nullptr);
this->state = AUDIO_SOURCE_STATE_STOPPED; assertTrue(this->data->loaded);
this->eventFinished.invoke();
this->bufferPosition = 0; // Release the buffers
buffersProcessed = 0; alSourceStop(this->source);
} this->detatchBuffers();
} else if(this->internalState == AUDIO_SOURCE_STATE_STOPPED) { this->internalState = AUDIO_SOURCE_STATE_STOPPED;
// Not yet playing. First thing we need to do is fill the buffers. this->eventStopped.invoke();
for(int32_t i = 0; i < AUDIO_SOURCE_BUFFER_COUNT; i++) { this->bufferPosition = 0;
this->fillBuffer(this->buffers[i]);
} } else {
assertUnreachable();
// Now attach the buffers }
this->attachBuffers(); }, getScene()->eventSceneUpdate);
}
// And begin playing
alSourcePlay(this->source); AudioSourceState AudioSource::getRealState() {
this->internalState = AUDIO_SOURCE_STATE_PLAYING; return this->internalState;
this->eventPlaying.invoke(); }
} else if(AUDIO_SOURCE_STATE_PAUSED) { void AudioSource::rewind() {
// Request to resume this->bufferPosition = 0;
alSourcePlay(this->source); }
this->eventResumed.invoke();
this->internalState = AUDIO_SOURCE_STATE_PLAYING; AudioAsset * AudioSource::getAudioData() {
return this->data;
} else { }
assertUnreachable();
} void AudioSource::setAudioData(AudioAsset *data) {
} else if(this->state == AUDIO_SOURCE_STATE_PAUSED) { this->data = data;
assertTrue(this->data != nullptr); this->rewind();
assertTrue(this->data->loaded); }
// Pause has been requested. void AudioSource::stop() {
if(this->internalState != AUDIO_SOURCE_STATE_PLAYING) return; this->state = AUDIO_SOURCE_STATE_STOPPED;
}
// We are playing something, pause it
alSourcePause(this->source); void AudioSource::play() {
this->internalState = AUDIO_SOURCE_STATE_PAUSED; this->state = AUDIO_SOURCE_STATE_PLAYING;
this->eventPaused.invoke(); }
} else if(this->state == AUDIO_SOURCE_STATE_STOPPED) { void AudioSource::pause() {
if(this->internalState == AUDIO_SOURCE_STATE_STOPPED) return; this->state = AUDIO_SOURCE_STATE_PAUSED;
}
assertTrue(this->data != nullptr);
assertTrue(this->data->loaded); void AudioSource::onDispose() {
assertTrue(this->ready);
// Release the buffers this->ready = false;
alSourceStop(this->source);
this->detatchBuffers(); alDeleteSources((ALuint)1, &this->source);
this->internalState = AUDIO_SOURCE_STATE_STOPPED; alDeleteBuffers((ALuint)AUDIO_SOURCE_BUFFER_COUNT, this->buffers);
this->eventStopped.invoke();
this->bufferPosition = 0;
} else {
assertUnreachable();
}
}
void AudioSource::onTransformUpdate() {
glm::vec3 position = this->transform->getWorldPosition();
alSource3f(this->source, AL_POSITION, position.x, position.y, position.z);
} }

View File

@ -1,133 +1,118 @@
// Copyright (c) 2023 Dominic Masters // Copyright (c) 2023 Dominic Masters
// //
// This software is released under the MIT License. // This software is released under the MIT License.
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#pragma once #pragma once
#include "dawnopenal.hpp" #include "dawnopenal.hpp"
#include "scene/SceneItemComponent.hpp" #include "scene/SceneItemComponent.hpp"
#include "asset/assets/AudioAsset.hpp" #include "asset/assets/AudioAsset.hpp"
#define AUDIO_SOURCE_BUFFER_COUNT 3 #define AUDIO_SOURCE_BUFFER_COUNT 3
#define AUDIO_SOURCE_BUFFER_SIZE 8192 #define AUDIO_SOURCE_BUFFER_SIZE 8192
namespace Dawn { namespace Dawn {
enum AudioSourceState { enum AudioSourceState {
AUDIO_SOURCE_STATE_STOPPED, AUDIO_SOURCE_STATE_STOPPED,
AUDIO_SOURCE_STATE_PLAYING, AUDIO_SOURCE_STATE_PLAYING,
AUDIO_SOURCE_STATE_PAUSED AUDIO_SOURCE_STATE_PAUSED
}; };
enum AudioSourcePlayMode { enum AudioSourcePlayMode {
AUDIO_PLAY_MODE_ALWAYS, AUDIO_PLAY_MODE_ALWAYS,
AUDIO_PLAY_MODE_UNPAUSED AUDIO_PLAY_MODE_UNPAUSED
}; };
class AudioSource : public SceneItemComponent { class AudioSource : public SceneItemComponent {
private: private:
ALuint source; ALuint source;
bool_t ready = false; bool_t ready = false;
ALuint buffers[AUDIO_SOURCE_BUFFER_COUNT]; ALuint buffers[AUDIO_SOURCE_BUFFER_COUNT];
size_t bufferPosition = 0; size_t bufferPosition = 0;
// Settings // Settings
enum AudioSourceState internalState = AUDIO_SOURCE_STATE_STOPPED; enum AudioSourceState internalState = AUDIO_SOURCE_STATE_STOPPED;
int32_t layer = 0; int32_t layer = 0;
AudioAsset *data = nullptr; AudioAsset *data = nullptr;
AudioSourcePlayMode playMode = AUDIO_PLAY_MODE_UNPAUSED;
/**
/** * Internally update the audio's state based on the current settings.
* Internally update the audio's state based on the current settings. */
*/ void updateAudioSource();
void updateAudioSource();
void fillBuffer(ALuint buffer);
void fillBuffer(ALuint buffer); void detatchBuffers();
void detatchBuffers(); void attachBuffers();
void attachBuffers();
// Events
// Events void onSceneUpdate();
void onSceneUpdate();
void onTransformUpdate(); public:
bool_t loop = false;
public: enum AudioSourceState state = AUDIO_SOURCE_STATE_STOPPED;
bool_t loop = false; AudioSourcePlayMode playMode;
enum AudioSourceState state = AUDIO_SOURCE_STATE_STOPPED;
Event<> eventPlaying;
Event<> eventPlaying; Event<> eventResumed;
Event<> eventResumed; Event<> eventPaused;
Event<> eventPaused; Event<> eventStopped;
Event<> eventStopped; Event<> eventFinished;
Event<> eventFinished; Event<> eventLooped;
Event<> eventLooped;
/**
/** * Creates an Audio Source item component.
* Creates an Audio Source item component. *
* * @param item SceneItem that this audio source is attached to.
* @param item SceneItem that this audio source is attached to. */
*/ AudioSource(SceneItem *item);
AudioSource(SceneItem *item);
/**
/** * Returns the real current state of the sound. Refer to getPlayingState
* Returns the real current state of the sound. Refer to getPlayingState * but basically the actually requested play state and what the hardware
* but basically the actually requested play state and what the hardware * and internal logic is doing may result in the actual state being a
* and internal logic is doing may result in the actual state being a * little different. You cannot control this, but you can read it.
* little different. You cannot control this, but you can read it. *
* * @return The actual current playing state.
* @return The actual current playing state. */
*/ AudioSourceState getRealState();
AudioSourceState getRealState();
/**
/** * Rewinds the audio source. At the time of writing this comment (23017) I
* Rewinds the audio source. At the time of writing this comment (23017) I * am unsure of the behaviour when rewinding whilst the source is active.
* am unsure of the behaviour when rewinding whilst the source is active. */
*/ void rewind();
void rewind();
/**
/** * Returns the current audio data for this source.
* Returns the current audio data for this source. *
* * @return Audio data that is atached to this source.
* @return Audio data that is atached to this source. */
*/ AudioAsset * getAudioData();
AudioAsset * getAudioData();
/**
/** * Sets the audio data for this source. Currently switching between the
* Sets the audio data for this source. Currently switching between the * audio data during playback may have undefined behavior.
* audio data during playback may have undefined behavior. *
* * @param data Data to set.
* @param data Data to set. */
*/ void setAudioData(AudioAsset *data);
void setAudioData(AudioAsset *data);
/**
/** * Stop playing this audio source. Shorthand for setting the state.
* Returns the play mode for the source. */
* void stop();
* @return Current play mode.
*/ /**
enum AudioSourcePlayMode getPlayMode(); * Play this audio source. Shorthand for state setting.
*/
/** void play();
* Sets the play mode for the source.
* /**
* @param mode Play Mode to use. * Pause this audio source. Shorthand for state setting.
*/ */
void setPlayMode(enum AudioSourcePlayMode mode); void pause();
/** void onStart() override;
* Stop playing this audio source. Shorthand for setting the state. void onDispose() override;
*/ };
void stop();
/**
* Play this audio source. Shorthand for state setting.
*/
void play();
/**
* Pause this audio source. Shorthand for state setting.
*/
void pause();
void onStart() override;
void onDispose() override;
};
} }

View File

@ -14,73 +14,67 @@ TicTacToeGame::TicTacToeGame(SceneItem *item) : SceneItemComponent(item) {}
void TicTacToeGame::onStart() { void TicTacToeGame::onStart() {
// Map tiles by tile number = tile // Map tiles by tile number = tile
auto tiles = getScene()->findComponents<TicTacToeTile>(); auto ts = getScene()->findComponents<TicTacToeTile>();
auto itTiles = tiles.begin(); auto itTiles = ts.begin();
while(itTiles != tiles.end()) { while(itTiles != ts.end()) {
this->tiles[(*itTiles)->tile] = *itTiles; this->tiles[(*itTiles)->tile] = *itTiles;
++itTiles; ++itTiles;
} }
// Listen // Listen
getScene()->eventSceneUpdate.addListener(this, &TicTacToeGame::onSceneUpdate); useEvent([&](float_t delta) {
} // Get mouse in screen space.
auto mouse = getGame()->inputManager.getAxis2D(INPUT_BIND_MOUSE_X, INPUT_BIND_MOUSE_Y);
mouse *= 2.0f;
mouse -= glm::vec2(1, 1);
void TicTacToeGame::onDispose() { Camera *camera = getScene()->findComponent<Camera>();
getScene()->eventSceneUpdate.removeListener(this, &TicTacToeGame::onSceneUpdate); if(camera == nullptr) return;
}
void TicTacToeGame::onSceneUpdate() { struct Ray3D ray;
// Get mouse in screen space. ray.origin = camera->transform->getWorldPosition();
auto mouse = getGame()->inputManager.getAxis2D(INPUT_BIND_MOUSE_X, INPUT_BIND_MOUSE_Y); ray.direction = camera->getRayDirectionFromScreenSpace(mouse);
mouse *= 2.0f;
mouse -= glm::vec2(1, 1);
Camera *camera = getScene()->findComponent<Camera>();
if(camera == nullptr) return;
struct Ray3D ray;
ray.origin = camera->transform->getWorldPosition();
ray.direction = camera->getRayDirectionFromScreenSpace(mouse);
// Find the hovered tile (if any)
TicTacToeTile *hovered = nullptr;
auto results = getPhysics()->raycast3DAll(ray);
auto itResult = results.begin();
while(itResult != results.end()) {
auto result = *itResult;
auto tile = result.collider->item->getComponent<TicTacToeTile>();
if(tile == nullptr) {
++itResult;
continue;
}
hovered = tile;
break;
}
// Now update the state of each tile, also get the state while we are at it // Find the hovered tile (if any)
std::map<uint8_t, enum TicTacToeTileState> tileMap; TicTacToeTile *hovered = nullptr;
auto results = getPhysics()->raycast3DAll(ray);
auto itTiles = tiles.begin(); auto itResult = results.begin();
while(itTiles != tiles.end()) { while(itResult != results.end()) {
auto t = itTiles->second; auto result = *itResult;
auto tile = result.collider->item->getComponent<TicTacToeTile>();
if(t == hovered) { if(tile == nullptr) {
if(t->tileState == TIC_TAC_TOE_EMPTY && getGame()->inputManager.isPressed(INPUT_BIND_MOUSE_CLICK)) { ++itResult;
t->tileState = nextMove; continue;
nextMove = nextMove == TIC_TAC_TOE_NOUGHT ? TIC_TAC_TOE_CROSS : TIC_TAC_TOE_NOUGHT;
} else if(t->tileState == TIC_TAC_TOE_EMPTY) {
t->hovered = true;
} }
} else {
t->hovered = false; hovered = tile;
break;
} }
tileMap[itTiles->second->tile] = itTiles->second->tileState;
++itTiles;
}
// Determine winner // Now update the state of each tile, also get the state while we are at it
std::vector<uint8_t> winningCombo; std::map<uint8_t, enum TicTacToeTileState> tileMap;
auto winner = ticTacToeDetermineWinner(tileMap, &winningCombo);
auto itTiles = tiles.begin();
while(itTiles != tiles.end()) {
auto t = itTiles->second;
if(t == hovered) {
if(t->tileState == TIC_TAC_TOE_EMPTY && getGame()->inputManager.isPressed(INPUT_BIND_MOUSE_CLICK)) {
t->tileState = nextMove;
nextMove = nextMove == TIC_TAC_TOE_NOUGHT ? TIC_TAC_TOE_CROSS : TIC_TAC_TOE_NOUGHT;
} else if(t->tileState == TIC_TAC_TOE_EMPTY) {
t->hovered = true;
}
} else {
t->hovered = false;
}
tileMap[itTiles->second->tile] = itTiles->second->tileState;
++itTiles;
}
// Determine winner
std::vector<uint8_t> winningCombo;
auto winner = ticTacToeDetermineWinner(tileMap, &winningCombo);
}, getScene()->eventSceneUpdate);
} }

View File

@ -17,8 +17,5 @@ namespace Dawn {
TicTacToeGame(SceneItem *item); TicTacToeGame(SceneItem *item);
void onStart() override; void onStart() override;
void onDispose() override;
void onSceneUpdate();
}; };
} }