diff options
| author | Tim Redfern <tim@gray.(none)> | 2012-11-09 18:55:44 +0000 |
|---|---|---|
| committer | Tim Redfern <tim@gray.(none)> | 2012-11-09 18:55:44 +0000 |
| commit | eda90b505d3a583e0c3788ca1ad924d75b02fe01 (patch) | |
| tree | f533eee587bca2a4f3cddcf70abddc91b39d6cd8 /vfg/src | |
| parent | b5aba6fcbf2847735b0c43e84d0933797c73f581 (diff) | |
levels working, lyrics loading
Diffstat (limited to 'vfg/src')
| -rwxr-xr-x | vfg/src/music.cpp | 148 | ||||
| -rwxr-xr-x | vfg/src/music.h | 133 | ||||
| -rwxr-xr-x | vfg/src/testApp.cpp | 23 | ||||
| -rwxr-xr-x | vfg/src/testApp.h | 4 |
4 files changed, 204 insertions, 104 deletions
diff --git a/vfg/src/music.cpp b/vfg/src/music.cpp index 096e630..29b1ef6 100755 --- a/vfg/src/music.cpp +++ b/vfg/src/music.cpp @@ -2,18 +2,11 @@ //event times & durations are absolute integer milliseconds
//---------------------------------------------------------------------------------------------------------------------------------------------
-note::note(int n,int v,int d){
- num=n;
- velocity=v;
- duration=d;
- activated=false;
-}
-//---------------------------------------------------------------------------------------------------------------------------------------------
-//---------------------------------------------------------------------------------------------------------------------------------------------
musicscore::musicscore() {
timeframe=2000;
flake.loadImage("flake.png");
flake.setAnchorPercent(0.5,0.5);
+ missedLast=false;
}
void musicscore::parseMidi(string filename){
// millis = 60000 / (BPM * PPQ)
@@ -86,10 +79,9 @@ void musicscore::parseMidi(string filename){ while (++iter2 != events.end()) { if ((iter1->second->num==iter2->second->num)&&(iter2->second->duration==128)) { iter1->second->duration=iter2->first-iter1->first;
- iter1->second->updown=iter1->second->num<n?-1:iter1->second->num==n?0:1;
n=iter1->second->num; notes[iter1->first]=iter1->second; - printf("%i: noteon %i %i %i\n",iter1->first,iter1->second->num,iter1->second->duration,iter1->second->updown); + //printf("%i: noteon %i %i\n",iter1->first,iter1->second->num,iter1->second->duration); break; } } @@ -98,97 +90,96 @@ void musicscore::parseMidi(string filename){ iter1 = notes.end(); iter1--;
printf("processed %s: length %f, %i notes in %f seconds\n",filename.c_str(),((float)(iter1->first+iter1->second->duration)*.001f),notes.size(),ofGetElapsedTimef()-wt);
-
-//decimate notes to generate flakes that can be interacted with
- int noteThresh=1000;
- note *lastNote=notes.begin()->second;
- int lastTime=0;
- stars[notes.begin()->first]=notes.begin()->second;
- for (iter1 = notes.begin(); iter1 != notes.end(); iter1++) {
- if ((iter1->second->num/5!=lastNote->num/5)||(iter1->first-lastTime>noteThresh)) {
- stars[iter1->first]=iter1->second;
+}
+void musicscore::makeFlakes(int threshStart,int threshEnd){
+ //decimate notes to generate flakes that can be interacted with
+ map<int,note*>::iterator iter;
+ note *lastNote=notes.begin()->second;
+ int lastTime=0;
+ iter = notes.end();
+ iter--;
+ float songDuration=iter->first;
+ flakes[notes.begin()->first]=notes.begin()->second;
+ for (iter = notes.begin(); iter != notes.end(); iter++) {
+ float songPos=((float)iter->first)/songDuration;
+ if ((iter->second->num/5!=lastNote->num/5)||(iter->first-lastTime>((songPos*threshEnd)+((1.0f-songPos)*threshStart)))) {
+ flakes[iter->first]=iter->second;
}
- lastNote=iter1->second;
- lastTime=iter1->first;
- }
-
- interactionThresh=200; //how long player has to respond
- missedTime=-1;
-
-
+ lastNote=iter->second;
+ lastTime=iter->first;
+ }
}
void musicscore::setTimeframe(int millis) {timeframe=millis;}
-void musicscore::draw() {
+void musicscore::draw(levelscore *levels) {
ofEnableAlphaBlending();
int scoreStart=ofGetElapsedTimeMillis()-startTime;
int scoreEnd=scoreStart+timeframe;
- //temporary drawing method 46h - 52h
+ //note drawing 46h - 52h
int numnotes=16;
int firstnote=70;
float widthStep=((float)ofGetWidth())/numnotes;
float heightStep=((float)ofGetHeight())/timeframe;
map<int,note*>::iterator iter;
- for (iter = notes.lower_bound(scoreStart); iter != notes.upper_bound(scoreEnd); ++iter) {
+ //draw notes for reference
+ for (iter = notes.lower_bound(scoreStart); iter != notes.upper_bound(scoreEnd); ++iter) {
int thisnote=iter->second->num-firstnote;
int thisstart=iter->first-scoreStart;
int thislength=iter->second->duration;
ofSetColor(ofColor::fromHsb(((float)thisnote*255)/numnotes,200,100));
ofRect(thisnote*widthStep,ofGetHeight()-(thisstart*heightStep),widthStep,-(thislength*heightStep));
-
- //different methods for generating flakes
- //ideally theres a variable clumping factor, this means pre-processing the flakes though
-
- //ofSetColor(ofColor::fromHsb(((float)thisnote*255)/numnotes,200,255));
-
- //flake.draw((thisnote+0.5f)*widthStep,ofGetHeight()-(thisstart*heightStep));
- //flake.draw((iter->second->updown*ofGetWidth()*0.33)+(ofGetWidth()*0.5),ofGetHeight()-(thisstart*heightStep));
- //flake.draw((((thisnote/5)*5)+3.5f)*widthStep,ofGetHeight()-(thisstart*heightStep));
}
- for (iter = stars.lower_bound(scoreStart-200); iter != stars.upper_bound(scoreEnd); ++iter) { //added extra 200ms for flake to leave screen
+ //draw flakes
+ for (iter = flakes.lower_bound(scoreStart-200); iter != flakes.upper_bound(scoreEnd); ++iter) { //extra 200ms for flake to leave screen
int thisnote=iter->second->num-firstnote;
int thisstart=iter->first-scoreStart;
int thislength=iter->second->duration;
-
- // check player interaction
- if (thisstart<interactionThresh) {
- //this star needs to be interacted with
- if (((thisnote/5)+1)==playerKey) {
- //success!
- iter->second->playerActivated();
- }
- }
if (iter->second->activated) ofSetColor(255,255,255);
else ofSetColor(ofColor::fromHsb(((float)thisnote*255)/numnotes,200,255));
flake.draw((((thisnote/5)*5)+3.5f)*widthStep,ofGetHeight()-(thisstart*heightStep),flake.getWidth()/2,flake.getHeight()/2);
}
- //check for unactivated stars. must be a better way
- missedTime=-1;
- for (iter = stars.upper_bound(scoreStart); iter != stars.lower_bound(0); --iter) {
- if (!iter->second->activated) missedTime=scoreStart-iter->first;
- else break;
+ //check for unactivated flakes within this segment: is there a more efficient way?
+ //is it the number of flakes they can lose per segment?
+ missedFlakes=0;
+ missedLast=false;
+ for (iter = flakes.lower_bound(levels->getLowerBound(levels->getLevel(scoreStart))); iter != flakes.upper_bound(scoreStart); ++iter){
+ if (!iter->second->activated) {
+ missedFlakes++;
+ }
+ missedLast=!iter->second->activated;
}
ofDisableAlphaBlending();
}
-void musicscore::playerControl(int key){
- //0-3 - 0 is off
- playerKey=key;
+void musicscore::playerControl(int key,int threshold){
+ map<int,note*>::iterator iter;
+ int scoreTime=ofGetElapsedTimeMillis()-startTime;
+ for (iter = flakes.lower_bound(scoreTime-threshold); iter != flakes.upper_bound(scoreTime+threshold); ++iter) {
+ iter->second->activate();
+ }
}
//---------------------------------------------------------------------------------------------------------------------------------------------
-song::song(string backfile,string melfile,string notefile) {
+song::song(string backfile,string melfile,string musfile,string lyricfile,string levelfile) {
backing.loadSound(backfile);
melody.loadSound(melfile);
- notes.parseMidi(notefile);
+ notes.parseMidi(musfile);
+ lyrics.load(lyricfile);
+ levels.load(levelfile);
isPlaying=false;
- missedInterval=5000;
+ keyThresh=200;
}
void song::setTimeframe(int millis) {notes.setTimeframe(millis);}
+void song::setKeythresh(int millis) {keyThresh=millis;}
+void song::setFlakeThresh(int tS,int tE) {
+ fThreshStart=tS;
+ fThreshEnd=tE;
+}
void song::play() {
backing.play();
melody.play();
startTime=ofGetElapsedTimeMillis();
notes.startTime=startTime;
isPlaying=true;
+ notes.makeFlakes(fThreshStart,fThreshEnd);
}
void song::stop() {
backing.stop();
@@ -200,24 +191,33 @@ void song::preRoll(long preroll) { notes.startTime=startTime;
isPreroll=true;
isPlaying=true;
+ notes.makeFlakes(fThreshStart,fThreshEnd);
}
void song::draw(){
- //how to deal with end/ track length/ part of game?
- if (isPreroll) {
- if (startTime<ofGetElapsedTimeMillis()) {
- backing.play();
- melody.play();
- isPreroll=false;
+ int songTime=ofGetElapsedTimeMillis()-startTime;
+ if (isPlaying) {
+ if (isPreroll) {
+ if (startTime<ofGetElapsedTimeMillis()) {
+ backing.play();
+ melody.play();
+ isPreroll=false;
+ }
}
+ if (notes.missedLast) {
+ melody.setVolume(0.0f);
+ if (levels.getLives(songTime)) {
+ if (notes.missedFlakes>levels.getLives(songTime)) {
+ //work out score
+ stop();
+ }
+ }
+ }
+ else melody.setVolume(1.0f);
+ notes.draw(&levels);
}
- if (notes.missedTime>0) {
- if (notes.missedTime>missedInterval) stop();
- else melody.setVolume(0.0f); //1.0f-((float)notes.missedTime/(float)missedInterval));
- }
- else melody.setVolume(1.0f);
- notes.draw();
+
+ ofDrawBitmapString(ofToString((float)songTime/1000.0f,3)+" "+ofToString(levels.getLevel(songTime))+" "+ofToString(notes.missedFlakes)+" of "+ofToString(levels.getLives(songTime)),10,ofGetHeight()-15);
}
void song::playerControl(int key){
- //0-3 - 0 is off
- notes.playerControl(key);
+ notes.playerControl(key,keyThresh);
} diff --git a/vfg/src/music.h b/vfg/src/music.h index 39ffd95..292e05f 100755 --- a/vfg/src/music.h +++ b/vfg/src/music.h @@ -5,15 +5,75 @@ //event times are absolute integer milliseconds
//---------------------------------------------------------------------------------------------------------------------------------------------
+class levelscore {
+ public:
+ void load(string filename) {
+ ofxXmlSettings XML;
+ if( !XML.loadFile(filename) ){
+ printf("unable to load %s check data/ folder\n",filename.c_str());
+ }else{
+ if(XML.pushTag("VFxmas")) {
+ for (int i=0;i<XML.getNumTags("Level");i++) {
+ levels[XML.getAttribute("Level", "Time",0,i)]=XML.getAttribute("Level", "Lives",0,i);
+ }
+ printf("processed %s: %i difficulty levels \n",filename.c_str(),levels.size());
+ }
+ }
+ }
+ int getLives(int time) {
+ map<int,int>::iterator iter;
+ int lives=0;
+ for (iter = levels.begin(); iter != levels.end(); ++iter) {
+ if (iter->first<=time) lives=iter->second;
+ else break;
+ }
+ return lives;
+ }
+ int getLevel(int time) {
+ map<int,int>::iterator iter;
+ int level=-1;
+ for (iter = levels.begin(); iter != levels.end(); ++iter) {
+ if (iter->first<=time) level++;
+ else break;
+ }
+ return level;
+ }
+ int getLowerBound(int level) {
+ map<int,int>::iterator iter=levels.begin();
+ int bound=0;
+ for (int i=0;i<=level;i++) {
+ bound=iter->first;
+ iter++;
+ }
+ return bound;
+ }
+ private:
+ map<int,int> levels;
+};
+//---------------------------------------------------------------------------------------------------------------------------------------------
class note {
public:
- note(int n,int v,int d=0);
+ note(int n,int v,int d=0) {
+ num=n;
+ velocity=v;
+ duration=d;
+ activated=false;
+ }
int num;
int velocity;
int duration; //may be needed another time?
- int updown; //-1 0 1 used for 3-button interaction
bool activated;
- void playerActivated() { activated=true; }
+ void activate() { activated=true; }
+};
+//---------------------------------------------------------------------------------------------------------------------------------------------
+class lyric {
+ public:
+ lyric(string s,int d) {
+ text=s;
+ duration=d;
+ }
+ string text;
+ int duration;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class score {
@@ -27,6 +87,23 @@ class score { class lyricscore: public score {
//draws lyrics to screen for a certain time
public:
+ void load(string filename) {
+ if( !XML.loadFile(filename) ){
+ printf("unable to load %s check data/ folder\n",filename.c_str());
+ }else{
+ int multiplier=1000/XML.getAttribute("VFxmas", "timebase",0,0);
+ if(XML.pushTag("VFxmas")) {
+ for (int i=0;i<XML.getNumTags("Lyric");i++) {
+ int in=XML.getAttribute("Lyric", "In",0,i)*multiplier;
+ lyrics[in]=new lyric(XML.getValue("Lyric","",i),(XML.getAttribute("Lyric", "Out",0,i)*multiplier)-in);
+ }
+ printf("processed %s: %i lyrics \n",filename.c_str(),lyrics.size());
+ }
+
+ }
+ }
+ private:
+ map<int,lyric*> lyrics;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class musicscore: public score {
@@ -35,31 +112,30 @@ class musicscore: public score { musicscore();
void parseMidi(string filename);
void setTimeframe(int millis);
- void draw();
-
- void playerControl(int key);
- //in wrong object?
- int missedTime;
+ void draw(levelscore *levels);
+ void playerControl(int key,int threshold);
+ void makeFlakes(int threshStart,int threshEnd);
+
+ int missedFlakes;
+ bool missedLast;
+ bool perfect;
+
private:
- map<int,note*> notes; - map<int,note*> stars;
+ map<int,note*> notes;
+ map<int,note*> flakes;
int timeframe;
ofImage flake;
-
- //in wrong object?
- int interactionThresh;
-
-
- int playerKey;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
class song {
public:
- song(string backfile,string melfile,string musfile);
+ song(string backfile,string melfile,string musfile,string lyricfile,string levelfile);
void play();
void stop();
void preRoll(long preroll);
void setTimeframe(int millis);
+ void setFlakeThresh(int tS,int tE);
+ void setKeythresh(int millis);
void draw();
bool isPlaying;
void playerControl(int key);
@@ -68,12 +144,31 @@ class song { ofSoundPlayer melody;
lyricscore lyrics;
musicscore notes;
+ levelscore levels;
long startTime;
bool isPreroll;
-
- int missedInterval;
+ int fThreshStart,fThreshEnd,keyThresh;
};
//---------------------------------------------------------------------------------------------------------------------------------------------
+/*
+Game
+Animation & Sound Demo – NK to overlay latest version of Deck the Halls on 10 second animated sequence by COB Wednesday 7th November for visual and aural aesthetic sign-off. RM to send through latest version of Deck the Halls today (6th November).
+Game Development – TR presented initial demo today. Usability looks good. NK to provide first suite of graphics by COB Wednesday 7th November.
+Latency Test – TR and GK to perform end-to-end latency test next Monday 12th November once Vodafone have connected the 1800 number to the 01 number. Any issues noted in the testing to be flagged to BL.
+Game Over – Players who miss a certain amount of notes in a row will be kicked out of the game early. The number of notes that can be missed in a row will decrease as the game goes on (subject to testing and tweaking):
+
+Stage 1 – N/A (it will not be possible to be kicked out in Stage 1)
+Stage 2 – 5 notes missed will mean Game Over
+Stage 3 – 4 notes missed will mean Game Over
+Stage 4 – 3 notes missed will mean Game Over
+
+Scoring – Scoring will be based on the level of the game you achieve. There will be 4 scoring brackets (subject to testing and tweaking):
+
+Scoring Bracket 1 - Those who make it to Level 2 (see above - it's not possible to be kicked out in Level 1)
+Scoring Bracket 2 – Those who make it to Level 3
+Scoring Bracket 3 – Those who make it to Level 4
+Scoring Bracket 4 – Those who don't miss any notes in Level 4
+*/
diff --git a/vfg/src/testApp.cpp b/vfg/src/testApp.cpp index c0c3671..dc450a2 100755 --- a/vfg/src/testApp.cpp +++ b/vfg/src/testApp.cpp @@ -2,10 +2,14 @@ //-------------------------------------------------------------- void testApp::setup(){ - testsong=new song("VODA_MUS_DeckTheHalls-Backing_v.1.3.mp3","VODA_MUS_DeckTheHalls-Melody_v.1.3.mp3","MIDI_DeckTheHalls_Test.1.3.xml"); - testsong->setTimeframe(10000); - testsong->preRoll(250); + //for (float i=0;i<1.2;i+=0.1) printf("%f in level %i bound %f\n",i,lives->getLevel(i),lives->getLowerBound(lives->getLevel(i))); + + testsong=new song("VODA_MUS_DeckTheHalls-Backing_v.1.5.mp3","VODA_MUS_DeckTheHalls-Melody_v.1.5.mp3","MIDI_DeckTheHalls_MIDI.1.5.xml","Lyrics_DeckTheHalls.1.5.xml","Levels_DeckTheHalls.1.5.xml"); + testsong->setTimeframe(2500); + testsong->setFlakeThresh(1000,100); + testsong->preRoll(250); + ofSetBackgroundAuto(false); ofBackground(0,0,0); } @@ -20,15 +24,14 @@ void testApp::update(){ //-------------------------------------------------------------- void testApp::draw(){ - ofEnableAlphaBlending(); + ofEnableAlphaBlending(); //ofBackground(0,0,0,0.1); - ofSetColor(0,0,0,100); + ofSetColor(0,0,0,50); ofRect(0,0,ofGetWidth(),ofGetHeight()); - if (testsong->isPlaying) testsong->draw(); - else { - ofSetColor(255,255,255); - ofDrawBitmapString("game over!", (ofGetWidth()/2)-25,(ofGetHeight()/2)-5); - } + ofSetColor(255,255,255); + testsong->draw(); + if (!testsong->isPlaying) ofDrawBitmapString("game over!", (ofGetWidth()/2)-25,(ofGetHeight()/2)-5); + } //-------------------------------------------------------------- diff --git a/vfg/src/testApp.h b/vfg/src/testApp.h index 5a8805a..0765b4f 100755 --- a/vfg/src/testApp.h +++ b/vfg/src/testApp.h @@ -44,6 +44,8 @@ class game { vector<song*> songs; }; + + class testApp : public ofBaseApp{ public: @@ -62,7 +64,7 @@ class testApp : public ofBaseApp{ void dragEvent(ofDragInfo dragInfo); void gotMessage(ofMessage msg); - song* testsong; + song *testsong; }; |
