// This Staff class was created by Gail to support procedurally generated notes. // The original Staff class was renamed Staff2 (which now extends this class). // HOOK: Extend this class to change behaviours of the staff. You may even wish // to completely change the staff into some other background image, etc. class Staff { protected final int STATE_STAGE_1 = 0; // show letters on notes protected final int STATE_STAGE_2 = 1; // show letters only at left protected final int STATE_STAGE_3 = 2; // don't show letters, increase speeds protected final int LAST_STATE = STATE_STAGE_3; protected int m_state; protected int m_timeInState; protected int m_elementSpacing; protected ArrayList m_scrollElements; protected int m_scrollSpeed; protected SpeedChange m_lastSpeedChange; protected PointsBar m_points_bar; protected long m_numElementsAdded; protected int m_numSpeedChanges; protected int m_speedValueIndex; protected PFont m_helperFont; protected final float[] speedValues = { Config.initialScrollSpeed, Config.initialScrollSpeed*1.3, Config.initialScrollSpeed*1.6, Config.initialScrollSpeed*2.0 }; protected char[] noteMap = new char[] { 'f', 'e', 'd', 'c', 'b', 'a', 'g', 'f', 'e' }; protected boolean[] noteOnSpace = new boolean[] { false, true, false, true, false, true, false, true, false }; protected int[] noteLineOrSpaceIndex = new int[] { 0, 0, 1, 1, 2, 2, 3, 3, 4 }; public final int barColor = 80; public final int lineColor = 0; public final int lineWeight = 4; public final int numberOfLines = 5; public final int numberOfSpaces = numberOfLines - 1; // Music notes on a staff from http://www.free-online-piano-lessons.com/images/StaffGuide.gif // ---------------- F // E // ---------------- D // C // ---------------- B // A // ---------------- G // F // ---------------- E ///////////////////////////////////////////////// public Staff() { initialize(); } public void restart() { initialize(); } public void initialize() { m_scrollElements = new ArrayList(); m_helperFont = loadFont("Helvetica-20.vlw"); m_elementSpacing = Config.initialElementSpacing; m_scrollSpeed = (int)speedValues[0]; m_numElementsAdded = 0; m_numSpeedChanges = 0; m_speedValueIndex = 0; m_lastSpeedChange = null; m_points_bar = new PointsBar(); m_state = STATE_STAGE_1; m_timeInState = 0; println("STAGE " + ((m_state - STATE_STAGE_1) + 1)); for (int i=0; i < Config.initialNumElementsReady; i++) generateScrollElement(); } ///////////////////////////////////////////////// // HOOK: Override to customize key press helpers public boolean showKeyPressHelpers() { return m_state == STATE_STAGE_1; } ///////////////////////////////////////////////// public int getInterval() { int interval = Config.staffHeight / numberOfLines; interval -= interval/numberOfLines; // offset so that there is some top and bottom padding return interval; } ///////////////////////////////////////////////// public int getLineHeight(int lineNum) // lineNum indexed from 0 { return (getInterval() * (lineNum+1)) + Config.gamePadding; } ///////////////////////////////////////////////// public PointsBar getPointsBar() { return m_points_bar; } ///////////////////////////////////////////////// public void setScrollSpeed(int newSpeed) { m_scrollSpeed = newSpeed; } public int getScrollSpeed() { return m_scrollSpeed; } ///////////////////////////////////////////////// public void setElementSpacing(int newSpace) { m_elementSpacing = newSpace; } public int getElementSpacing() { return m_elementSpacing; } ///////////////////////////////////////////////// protected int numElements() { return m_scrollElements.size(); } ///////////////////////////////////////////////// // HOOK: Override to generate scrolling elements in whatever // way you want to protected void generateScrollElement() { // Generate random stuff boolean madeSpeedChange = false; int prevNoteX; if (numElements() == 0) prevNoteX = Config.gameWidth - getElementSpacing(); else prevNoteX = ((ScrollElement)m_scrollElements.get(numElements()-1)).getX(); int noteX = prevNoteX + getElementSpacing(); prevNoteX = noteX; if (m_numElementsAdded % Config.speedChangeSpacing == Config.speedChangeSpacing-1) { //if (m_numSpeedChanges < speedValues.length || random(1.0) < 0.6) { int oldSpeed = getScrollSpeed(); SpeedChange oldChange = lastSpeedChange(); if (oldChange != null) { oldSpeed = oldChange.getSpeedChange(); } int newSpeed; m_numSpeedChanges++; if (m_numSpeedChanges < speedValues.length) { // The first few speed changes will increase the speed to get the player used to // all of the possibilities newSpeed = (int)speedValues[m_speedValueIndex = m_numSpeedChanges]; } else { // After all speeds have been seen once, we randomly slow down or speed up if (m_speedValueIndex <= 0) { m_speedValueIndex++; } else if (m_speedValueIndex >= speedValues.length - 1) { m_speedValueIndex--; } else { m_speedValueIndex = random(1) < 0.5 ? m_speedValueIndex + 1 : m_speedValueIndex - 1; } newSpeed = (int)speedValues[m_speedValueIndex]; } m_lastSpeedChange = new SpeedChange(this, noteX, getLineHeight(0), oldSpeed, newSpeed); m_scrollElements.add(m_lastSpeedChange); madeSpeedChange = true; } } /// Only do this if we didn't already make a speed change else if (!madeSpeedChange) { int newIdx = int(random(0, noteMap.length)); int noteY; int spaceOrLineIdx = noteLineOrSpaceIndex[newIdx]; if (noteOnSpace[newIdx]) { noteY = getLineHeight(spaceOrLineIdx-1) + 35; } else { noteY = getLineHeight(spaceOrLineIdx-1); } m_scrollElements.add(new Note(this, noteX, noteY, noteMap[newIdx])); } m_numElementsAdded++; } ///////////////////////////////////////////////// // HOOK: Override if needed (can probably avoid doing so) public boolean advance() { m_timeInState++; if (m_state < LAST_STATE && m_timeInState > Config.timePerStage) { m_state++; m_timeInState = 0; // Increase speeds if (m_state == STATE_STAGE_3) { for (int i=0; i < speedValues.length; i++) { speedValues[i] += Config.scrollSpeedChangeIncr; } } println("STAGE " + (m_state - STATE_STAGE_1 + 1)); } // Remove any notes that should be removed Iterator it = m_scrollElements.iterator(); int numRemoved = 0; while (it.hasNext()) { ScrollElement element = (ScrollElement)it.next(); if (element.removeMe()) { it.remove(); numRemoved++; } } if (numElements() < Config.numElementsLeftForRegen) { for (int i=0; i < Config.numElementsToRegen; i++) { generateScrollElement(); } //println("Regenerated " + Config.numElementsToRegen + " elements."); } // Advance all the scroll elements for (int i=0; i < numElements(); i++) { ((ScrollElement)m_scrollElements.get(i)).advance(); } // Return whether there are any notes left return numElements() > 0; } ///////////////////////////////////////////////// protected boolean firstElementIsNote() { return ((ScrollElement)m_scrollElements.get(0)).isNote(); } ///////////////////////////////////////////////// protected SpeedChange lastSpeedChange() { SpeedChange speed = null; // // Find the first note // int idx = numElements()-1; // while (idx >= 0) // { // ScrollElement element = (ScrollElement)m_scrollElements.get(idx); // // if (element.isSpeedChange() && element.inPlay()) // { // speed = ((SpeedChange)element); // break; // } // idx--; // } // FASTER speed = m_lastSpeedChange; return speed; } ///////////////////////////////////////////////// protected Note nextNote() { Note note = null; // Find the first note int idx = 0; while (idx < numElements()) { ScrollElement element = (ScrollElement)m_scrollElements.get(idx); //println(element.isNote() + " " + element.inPlay()); //if (element.isNote()) println(" (note: " + ((Note)element).getNote() + ")"); if (element.isNote() && element.inPlay() && !element.offScreen()) { note = ((Note)element); break; } idx++; } //println(); return note; } ///////////////////////////////////////////////// // HOOK: Override this method to do custom checking // for key presses public void checkAndActKeyPress(char key) { Note note = nextNote(); if (note != null && note.getNote() == key) { // you pushed the right key hitCorrectNote(); } else { // you pushed the wrong key hitIncorrectNote(); } } ///////////////////////////////////////////////// // HOOK: Override this method to do custom action when // correct key is pressed public void hitCorrectNote() { nextNote().hit(); } ///////////////////////////////////////////////// // HOOK: Override this method to do custom action when // incorrect key is pressed public void hitIncorrectNote() { Note nextNote = nextNote(); if (nextNote != null) nextNote.miss(); } ///////////////////////////////////////////////// public void incrementPoints() { m_points_bar.increment(); } public void decrementPoints() { m_points_bar.decrement(); } ///////////////////////////////////////////////// public void draw() { /********************************** ***** Draw staff lines************ **********************************/ stroke(lineColor); strokeWeight(lineWeight); fill(lineColor); for (int i=0;i