Support for text dialog, audio handling, and click to continue support.

master
sigonasr2 1 year ago
parent 1493faa8e5
commit 7e63a0a875
  1. 2
      olcCodeJam2023Entry/Image.h
  2. 19
      olcCodeJam2023Entry/Scenario.cpp
  3. 7
      olcCodeJam2023Entry/Scenario.h
  4. 1
      olcCodeJam2023Entry/Sound.h
  5. 83
      olcCodeJam2023Entry/Textbox.cpp
  6. 8
      olcCodeJam2023Entry/Textbox.h
  7. 18
      olcCodeJam2023Entry/Unit.cpp
  8. 2
      olcCodeJam2023Entry/Unit.h
  9. 30
      olcCodeJam2023Entry/VirusAttack.cpp
  10. 2
      olcCodeJam2023Entry/VirusAttack.h
  11. BIN
      olcCodeJam2023Entry/assets/hooded_figure.png
  12. BIN
      olcCodeJam2023Entry/assets/spook_hooded_figure.png
  13. 15
      olcCodeJam2023Entry/olcPGEX_AudioSource.h

@ -40,5 +40,7 @@ enum Image{
GUIDE,
ROUND_BAR,
SEGMENT_BAR,
HOODED_FIGURE,
SPOOK_HOODED_FIGURE,
};

@ -1,9 +1,14 @@
#include "Scenario.h"
Scenario::Scenario(VirusAttack*game)
:game(game){}
:game(game){
dialog.SetVisible(false);
}
void Scenario::Start(){}
void Scenario::_Update(){
initialWaitTimer=std::max(0.f,initialWaitTimer-game->GetElapsedTime());
Update();
}
void Scenario::_Draw(){
@ -13,10 +18,18 @@ void Scenario::_Draw(){
Stage1::Stage1(VirusAttack*game)
:Scenario(game){}
void Stage1::Start(){
game->unitMetersGreyedOut=true;
game->playerInControl=false;
}
void Stage1::Update(){
switch(state){
case 0:{
dialog.Initialize("Hello Hacker, thank you for taking on this request for me.",{24,64},"",game->IMAGES[HOODED_FIGURE].get(),{378,28},game->SOUNDS[Sound::VOICEOVER].get());
}break;
}
}
void Stage1::Draw(){
dialog.UpdateAndDraw({24,64},game,game->player_resources,game->IMAGES,game->GetTotalUsedMemory(),game->currentLevel->availableMemory);
}

@ -2,19 +2,24 @@
#include "VirusAttack.h"
class Scenario{
VirusAttack*game;
public:
Scenario(VirusAttack*game);
virtual void Start();
void _Update();
virtual void Update()=0;
void _Draw();
virtual void Draw()=0;
protected:
VirusAttack*game;
int state=0;
Textbox dialog;
float initialWaitTimer=3;
};
class Stage1:public Scenario{
public:
Stage1(VirusAttack*game);
void Start()override;
void Update()override;
void Draw()override;
};

@ -6,4 +6,5 @@ enum class Sound{
COSMOS,
BOSS1,
BOSS2,
VOICEOVER,
};

@ -4,7 +4,7 @@
Textbox::Textbox(){};
void Textbox::Initialize(std::string text,vf2d pos,std::string headerText,vf2d maxSize,std::vector<Memory>resourceCost,float letterDisplayDelay)
void Textbox::Initialize(std::string text,vf2d pos,std::string headerText,Renderable*boxImg,vf2d maxSize,Audio*dialogSound,std::vector<Memory>resourceCost,float letterDisplayDelay)
{
if(GetCurrentString()!=text){ //Make sure this is actually a new textbox
SetDefaults();
@ -13,6 +13,14 @@ void Textbox::Initialize(std::string text,vf2d pos,std::string headerText,vf2d m
this->maxSize=maxSize;
this->resourceCost=resourceCost;
this->letterDisplayDelay=letterDisplayDelay;
this->boxImg=boxImg;
if(this->dialogSound!=nullptr){
this->dialogSound->Stop(soundHandle);
}
if(dialogSound!=nullptr){
this->dialogSound=dialogSound;
soundHandle=this->dialogSound->PlayCentered(1,audioVolume,true);
}
visible=true;
}
}
@ -28,11 +36,20 @@ void Textbox::SetDefaults(){
displayHeaderText="";
text="";
headerText="";
audioVolume=0;
continueWordTimer=0;
}
void Textbox::Update(PixelGameEngine*pge){
if(!visible)return;
if(!visible){
if(dialogSound!=nullptr){
audioVolume=std::max(0.f,audioVolume-pge->GetElapsedTime()*2);
dialogSound->SetVolume(soundHandle,audioVolume);
}
return;
}
lastLetterTime-=pge->GetElapsedTime();
continueWordTimer+=pge->GetElapsedTime();
if(lastLetterTime<=0){
if(textboxMarker<int(text.length()-1)){
std::string tempText=displayText;
@ -61,6 +78,19 @@ void Textbox::Update(PixelGameEngine*pge){
WrapText(tempHeaderText,headerText,displayHeaderText,lastHeaderWordMarker,lastHeaderWord);
}
textboxMarker++;
if(dialogSound!=nullptr){
audioVolume=std::min(1.f,audioVolume+0.01f*2);
dialogSound->SetVolume(soundHandle,audioVolume);
audioFadeOutDelay=2;
}
}else{
if(dialogSound!=nullptr){
audioFadeOutDelay=std::max(0.f,audioFadeOutDelay-0.01f);
if(audioFadeOutDelay<=0){
audioVolume=std::max(0.f,audioVolume-0.01f*2);
dialogSound->SetVolume(soundHandle,audioVolume);
}
}
}
maxSize.y=std::max(maxSize.y,float(pge->GetTextSizeProp(displayHeaderText).y+pge->GetTextSizeProp(displayText).y));
lastLetterTime=letterDisplayDelay;
@ -70,29 +100,46 @@ void Textbox::Update(PixelGameEngine*pge){
void Textbox::Draw(PixelGameEngine*pge,Resources&resources,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,int totalUsedMemory,int memoryLimit){
if(visible){
geom2d::rect<float>boxRect={pos-vf2d{3,3},maxSize+vf2d{6,6}};
geom2d::rect<float>boundingRect={pos-vf2d{3,3},maxSize+vf2d{6,6}};
if(resourceCost.size()>0){
boxRect.size.x+=36;
boxRect.size.y=std::max(36.f,boxRect.size.y);
boundingRect.size.x+=36;
boundingRect.size.y=std::max(36.f,boundingRect.size.y);
}
if(boxImg!=nullptr){
boundingRect.size.x+=26;
}
if(boundingRect.bottom().start.y>=pge->ScreenHeight()){
boundingRect.pos-={0,boundingRect.bottom().start.y-pge->ScreenHeight()};
}
if(boundingRect.right().start.x>=pge->ScreenWidth()){
boundingRect.pos-={boundingRect.right().start.x-pge->ScreenWidth(),0};
}
if(boundingRect.top().start.y<0){
boundingRect.pos+={0,-boundingRect.top().start.y};
}
if(boxRect.bottom().start.y>=pge->ScreenHeight()){
boxRect.pos-={0,boxRect.bottom().start.y-pge->ScreenHeight()};
if(boundingRect.left().start.x<0){
boundingRect.pos+={-boundingRect.left().start.x,0};
}
if(boxRect.right().start.x>=pge->ScreenWidth()){
boxRect.pos-={boxRect.right().start.x-pge->ScreenWidth(),0};
geom2d::rect<float>textboxRect=boundingRect;
if(boxImg!=nullptr){
textboxRect.pos.x+=26;
textboxRect.size.x-=50;
}
if(boxRect.top().start.y<0){
boxRect.pos+={0,-boxRect.top().start.y};
pge->FillRectDecal(boundingRect.pos,maxSize+vf2d{6,6},backCol);
pge->DrawRectDecal(boundingRect.pos+vf2d{1,1},maxSize+vf2d{4,4},WHITE);
pge->DrawDecal(boundingRect.pos+vf2d{3,3},IMAGES[MATRIX]->Decal(),{0.375,0.375},DARK_GREY);
if(boxImg!=nullptr){
pge->DrawDecal(boundingRect.pos+vf2d{3,3},boxImg->Decal());
}
if(boxRect.left().start.x<0){
boxRect.pos+={-boxRect.left().start.x,0};
pge->DrawRectDecal(boundingRect.pos+vf2d{3,3},{24,24},YELLOW);
pge->DrawShadowStringPropDecal(textboxRect.pos+vf2d{3,3},displayHeaderText,{245, 218, 66});
pge->DrawShadowStringPropDecal(textboxRect.pos+vf2d{3.f,float(3+pge->GetTextSizeProp(displayHeaderText).y)},displayText,{220,220,220});
if(textboxMarker==int(text.length()-1)){
std::string continueText="Click to Continue";
pge->DrawShadowStringPropDecal(textboxRect.pos+textboxRect.size-vf2d(pge->GetTextSizeProp(continueText))*vf2d{0.6,1}-vf2d{5,-9},continueText,{255,255,255,uint8_t(abs(sin(2*continueWordTimer))*255)},{0,0,0,uint8_t(abs(sin(2*continueWordTimer))*255)},{0.6,1});
}
pge->FillRectDecal(boxRect.pos,maxSize+vf2d{6,6},backCol);
pge->DrawRectDecal(boxRect.pos+vf2d{1,1},maxSize+vf2d{4,4},WHITE);
pge->DrawShadowStringPropDecal(boxRect.pos+vf2d{3,3},displayHeaderText,{245, 218, 66});
pge->DrawShadowStringPropDecal(boxRect.pos+vf2d{3.f,float(3+pge->GetTextSizeProp(displayHeaderText).y)},displayText,{220,220,220});
if(resourceCost.size()>0){
geom2d::rect<float>resourceBoxRect={boxRect.pos+vf2d{6+maxSize.x,0},{36,42}};
geom2d::rect<float>resourceBoxRect={textboxRect.pos+vf2d{6+maxSize.x,0},{36,42}};
pge->FillRectDecal(resourceBoxRect.pos,resourceBoxRect.size,backCol);
pge->DrawRectDecal(resourceBoxRect.pos+vf2d{1,1},resourceBoxRect.size-vf2d{2,2},WHITE);
vf2d contentPos=resourceBoxRect.pos+vf2d{3,3};

@ -9,12 +9,18 @@ class Textbox{
std::string displayHeaderText="";
std::string text="";
std::string displayText="";
Renderable*boxImg;
Audio*dialogSound;
int soundHandle=-1;
float audioFadeOutDelay=2;
vf2d pos={};
vf2d maxSize={};
float audioVolume=0;
float lastLetterTime=0;
float letterDisplayDelay=0.01;
int textboxMarker=-1;
int lastWordMarker=-1;
float continueWordTimer=0;
std::string lastWord="";
int lastHeaderWordMarker=-1;
std::string lastHeaderWord="";
@ -23,7 +29,7 @@ class Textbox{
Pixel backCol=CONSTANT::MESSAGE_BOX_DEFAULT_BACKCOL;
public:
Textbox();
void Initialize(std::string text,vf2d pos={},std::string headerText="",vf2d maxSize={120,1},std::vector<Memory>resourceCost={},float letterDisplayDelay=0.01);
void Initialize(std::string text,vf2d pos={},std::string headerText="",Renderable*boxImg=nullptr,vf2d maxSize={120,1},Audio*dialogSound=nullptr,std::vector<Memory>resourceCost={},float letterDisplayDelay=0.01);
void UpdateAndDraw(vf2d pos,PixelGameEngine*pge,Resources&resources,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,int totalUsedMemory,int memoryLimit);
std::string&GetCurrentString();

@ -483,7 +483,7 @@ void Unit::Draw(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderab
void Unit::DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){}
void Unit::_DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES){
void Unit::_DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool unitMetersGreyedOut){
DrawHud(game,IMAGES);
int initialBarX=ghostPos.x-GetMemorySize()/2*CONSTANT::BAR_SQUARE_SIZE.x-CONSTANT::BAR_SQUARE_SIZE.x/2;
int initialBarY=ghostPos.y-CONSTANT::BAR_SQUARE_SIZE.y-img.Sprite()->height/2-2;
@ -495,16 +495,16 @@ void Unit::_DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Rend
col=CONSTANT::HEALTH_COLOR;
}
if(range.index==i&&range.size>0){
col=CONSTANT::RANGE_COLOR;
col=unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::RANGE_COLOR;
}
if(atkSpd.index==i&&atkSpd.size>0){
col=CONSTANT::ATKSPD_COLOR;
col=unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::ATKSPD_COLOR;
}
if(moveSpd.index==i&&moveSpd.size>0){
col=CONSTANT::MOVESPD_COLOR;
col=unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::MOVESPD_COLOR;
}
if(procedure.index==i&&procedure.size>0){
col=CONSTANT::PROCEDURE_COLOR;
col=unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::PROCEDURE_COLOR;
}
};
@ -514,19 +514,19 @@ void Unit::_DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Rend
}
if(GetAtkSpd()>0){
game.FillRectDecal(vf2d{float(initialBarX)+atkSpd.index*CONSTANT::BAR_SQUARE_SIZE.x,
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*atkSpd.size-1,2},CONSTANT::ATKSPD_COLOR);
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*atkSpd.size-1,2},unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::ATKSPD_COLOR);
}
if(GetMoveSpd()>0){
game.FillRectDecal(vf2d{float(initialBarX)+moveSpd.index*CONSTANT::BAR_SQUARE_SIZE.x,
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*moveSpd.size-1,2},CONSTANT::MOVESPD_COLOR);
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*moveSpd.size-1,2},unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::MOVESPD_COLOR);
}
if(GetProcedure()>0){
game.FillRectDecal(vf2d{float(initialBarX)+procedure.index*CONSTANT::BAR_SQUARE_SIZE.x,
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*procedure.size-1,2},CONSTANT::PROCEDURE_COLOR);
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*procedure.size-1,2},unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::PROCEDURE_COLOR);
}
if(GetRange()>0){
game.FillRectDecal(vf2d{float(initialBarX)+range.index*CONSTANT::BAR_SQUARE_SIZE.x,
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*range.size-1,2},CONSTANT::RANGE_COLOR);
float(initialBarY)}-vf2d{0,1},CONSTANT::BAR_SQUARE_SIZE+vf2d{CONSTANT::BAR_SQUARE_SIZE.x*range.size-1,2},unitMetersGreyedOut?VERY_DARK_GREY:CONSTANT::RANGE_COLOR);
}
for(int i=0;i<GetMemorySize();i++){

@ -54,7 +54,7 @@ public:
virtual void Attack(Unit&victim,std::vector<std::shared_ptr<Unit>>&otherUnits)=0;
virtual void Draw(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES);
virtual void DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES);
void _DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES);
void _DrawHud(TileTransformedView&game,std::map<Image,std::unique_ptr<Renderable>>&IMAGES,bool unitMetersGreyedOut);
virtual void OnDeath(std::map<Sound,std::unique_ptr<Audio>>&SOUNDS);
bool IsFriendly();
bool IsSelected();

@ -62,6 +62,8 @@ void VirusAttack::InitializeImages(){
LoadImage(GUIDE,"assets/guide.png");
LoadImage(ROUND_BAR,"assets/round_bar.png");
LoadImage(SEGMENT_BAR,"assets/segmentBar.png",false,false);
LoadImage(HOODED_FIGURE,"assets/hooded_figure.png");
LoadImage(SPOOK_HOODED_FIGURE,"assets/spook_hooded_figure.png");
}
void VirusAttack::InitializeLevelData(){
@ -144,6 +146,7 @@ bool VirusAttack::OnUserCreate(){
testBox.SetVisible(false);
memoryAllocatorBox.Initialize(CONSTANT::MEMORY_ALLOCATOR_BOX_DISPLAY_STRING,{},CONSTANT::MEMORY_ALLOCATOR_BOX_HEADER_STRING);
memoryAllocatorBox.SetVisible(false);
platformCreationBox.SetVisible(false);
IMAGES[MINIMAP_OUTLINE]=std::make_unique<Renderable>();
IMAGES[MINIMAP_OUTLINE]->Create(64,64);
@ -160,7 +163,7 @@ bool VirusAttack::OnUserCreate(){
InitializeLevelData();
LoadLevel(STAGE1);
currentLevel->scenario->Start();
return true;
}
@ -243,6 +246,9 @@ void VirusAttack::InitializeGUIs(){
refresherButton=new QuickGUI::ImageButton(platformCreationList,*IMAGES[REFRESHER],{0.25,0.25},{float(ScreenWidth()-48),48.f+32*1},{20,20});
turretButton=new QuickGUI::ImageButton(platformCreationList,*IMAGES[TURRET],{0.25,0.25},{float(ScreenWidth()-48),48.f+32*2},{20,20});
memoryGuardButton=new QuickGUI::ImageButton(platformCreationList,*IMAGES[MEMORY_GUARD],{0.25,0.25},{float(ScreenWidth()-48),48.f+32*3},{20,20});
unitCreationList.DisplayAllControls(false);
platformCreationList.DisplayAllControls(false);
}
void VirusAttack::InitializeScenarios(){
@ -264,6 +270,7 @@ void VirusAttack::InitializeSounds(){
LoadSound(Sound::COSMOS,"cosmos.mp3");
LoadSound(Sound::BOSS1,"boss1.mp3");
LoadSound(Sound::BOSS2,"boss2.mp3");
LoadSound(Sound::VOICEOVER,"voice.mp3");
}
bool VirusAttack::UnitCreationClickHandled(){
@ -296,7 +303,7 @@ bool VirusAttack::UnitCreationClickHandled(){
#define EnableAndHoverCheck(UnitClass,Button,box) \
Button->Enable(CanAfford(player_resources,UnitClass::resourceCost)); \
if(Button->bHover){ \
box.Initialize(UnitClass::unitDescription, GetMousePos(), UnitClass::unitName,{120,36},UnitClass::resourceCost); \
box.Initialize(UnitClass::unitDescription, GetMousePos(), UnitClass::unitName,nullptr,{120,36},nullptr,UnitClass::resourceCost); \
hovering=true; \
if(CanAfford(player_resources,UnitClass::resourceCost)){ \
box.SetBackgroundColor(CONSTANT::MESSAGE_BOX_DEFAULT_BACKCOL); \
@ -657,22 +664,17 @@ void VirusAttack::RenderCollectionPoints(CollectionPoint*cp){
bool VirusAttack::OnUserUpdate(float fElapsedTime){
UpdateMatrixTexture(fElapsedTime);
HandleDraggingSelection();
HandleRightClickMove();
HandlePanAndZoom(fElapsedTime);
HandleMinimapClick();
if(playerInControl){
HandleDraggingSelection();
HandleRightClickMove();
HandlePanAndZoom(fElapsedTime);
HandleMinimapClick();
}
currentLevel->scenario->_Update();
AL.vecPos=game.ScreenToWorld(GetScreenSize()/2);
AL.fSoundFXVolume=std::min(1.f,game.GetWorldScale().x);
AL.OnUserUpdate(fElapsedTime);
if(GetKey(P).bPressed){
LoadLevel(STAGE1);
}
if(GetKey(O).bPressed){
LoadLevel(STAGE2);
}
for(auto&tile:TileManager::visibleTiles){
tile.second-=fElapsedTime;
}
@ -760,7 +762,7 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){
std::erase_if(resourceGainIcons,[](ResourceGainIcon&icon){return icon.lifetime<=0;});
for(auto&u:units){
u->_DrawHud(game,IMAGES);
u->_DrawHud(game,IMAGES,unitMetersGreyedOut);
}
DrawSelectionRectangle();

@ -84,6 +84,8 @@ private:
float memoryDisplayDelay=0;
bool memoryIncreased=true;
float memoryChangeTimer=2;
bool unitMetersGreyedOut=false; //If true, all but health meters show up as dark grey.
bool playerInControl=true;
vf2d randomBackgroundOffset;

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

@ -104,7 +104,7 @@ public:
// Instruct Audio Listener to load this sound (if not loaded already)
void LoadAudioSample(int ID, const char* fileName);
void PlayCentered(float speed = 1.0f, float vol = 1.0f, bool looping = false, bool paused = false);
int PlayCentered(float speed = 1.0f, float vol = 1.0f, bool looping = false, bool paused = false);
// Play the Audio Sample, with given parameters
int Play(vf2d pos, float speed = 1.0f, float vol = 1.0f, bool looping = false, bool paused = false);
@ -122,6 +122,7 @@ public:
// Adjust Volume
void SetVolume(float vol, float minVol = 0.0f, float maxVol = 1.0f);
void SetVolume(int handle,float vol);
// Set Default Parameters
void SetDefaults(float speed, float vol, float minVol, float maxVol, bool looping);
@ -140,7 +141,7 @@ void olcPGEX_AudioSource::LoadAudioSample(int ID, const char* fileName)
AL->LoadAudioSample(ID, fileName);
}
void olcPGEX_AudioSource::PlayCentered(float speed, float vol, bool looping, bool paused)
int olcPGEX_AudioSource::PlayCentered(float speed, float vol, bool looping, bool paused)
{
// Set parameters
fPlaySpeed = speed;
@ -158,6 +159,7 @@ void olcPGEX_AudioSource::PlayCentered(float speed, float vol, bool looping, boo
// Update Play status
bIsPlaying = true;
return handle;
}
int olcPGEX_AudioSource::Play(vf2d pos, float speed, float vol, bool looping, bool paused)
@ -231,6 +233,15 @@ void olcPGEX_AudioSource::ModulateAudio(float minPlaySpeed, float maxPlaySpeed,
AL->soloud.setRelativePlaySpeed(handle, fPlaySpeed);
}
void olcPGEX_AudioSource::SetVolume(int handle,float vol)
{
// Set volume
fVolume = vol;
// Instruct the Audio Listener to apply the volume change
AL->soloud.setVolume(handle, fVolume);
}
void olcPGEX_AudioSource::SetVolume(float vol, float minVol, float maxVol)
{
// Set volume

Loading…
Cancel
Save