clock: Refactoring

This commit is contained in:
Hajime Hoshi 2018-01-07 16:43:01 +09:00
parent 0b3495b81f
commit d12a3d4073
2 changed files with 43 additions and 41 deletions

View File

@ -261,7 +261,7 @@ func (c *Context) loop() {
written += int64(n)
fs := written/int64(bytesPerFrame) - prevWritten/int64(bytesPerFrame)
for fs > 0 {
clock.ProceedPrimaryTimer()
clock.ProceedAudioTimer()
fs--
}
prevWritten = written

View File

@ -12,6 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package clock manages game timers.
//
// There are three types of clocks internally:
//
// System clock:
// A clock offered by the OS.
//
// Audio clock:
// An audio clock that is used in the higher priority over the system clock.
// An audio clock might not exist when the audio is not used.
//
// Game clock:
// A clock representing the actual game progress.
// A game clock is basically updated based on the number of frames.
// A game clock is adjusted by the audio clock when needed.
package clock
import (
@ -23,10 +38,11 @@ import (
const FPS = 60
var (
primaryTime int64
lastPrimaryTime int64
audioTimeInFrames int64
lastAudioTimeInFrames int64
frames int64
logicalTime int64
gameTime int64
currentFPS float64
lastFPSUpdated int64
@ -50,10 +66,10 @@ func RegisterPing(pingFunc func()) {
m.Unlock()
}
// ProceedPrimaryTimer increments the primary time by a frame.
func ProceedPrimaryTimer() {
// ProceedAudioTimer increments the audio time by a frame.
func ProceedAudioTimer() {
m.Lock()
primaryTime++
audioTimeInFrames++
m.Unlock()
}
@ -71,7 +87,7 @@ func updateFPS(now int64) {
}
// Update updates the inner clock state and returns an integer value
// indicating how many logical frames the game should update.
// indicating how many game frames the game should update.
func Update() int {
m.Lock()
defer m.Unlock()
@ -82,49 +98,35 @@ func Update() int {
ping()
}
// Initialize logicalTime if needed.
if logicalTime == 0 {
logicalTime = n
// Initialize gameTime if needed.
if gameTime == 0 {
gameTime = n
}
t := n - logicalTime
t := n - gameTime
if t < 0 {
return 0
}
count := 0
// Logical clock:
// A clock that updated based on the number of frames.
//
// System clock:
// A clock that offered by the OS.
//
// Primary clock:
// A clock that is used in the higher priority over the system clock.
// Primary time is usually an audio time.
// Primary time might not exist when e.g. audio is not used.
syncWithSystemClock := false
// When sync is true, the logical time is forced to sync with the system clock.
sync := false
if primaryTime > 0 && lastPrimaryTime != primaryTime {
// If the primary clock is updated, use this.
if frames < primaryTime {
count = int(primaryTime - frames)
if audioTimeInFrames > 0 && lastAudioTimeInFrames != audioTimeInFrames {
// If the audio clock is updated, use this.
if frames < audioTimeInFrames {
count = int(audioTimeInFrames - frames)
}
lastPrimaryTime = primaryTime
sync = true
lastAudioTimeInFrames = audioTimeInFrames
syncWithSystemClock = true
} else {
// Use system clock when
// 1) Inc() is not called, or
// 2) the primary clock is not updated yet.
// As the primary clock can be updated discountinuously, the system clock is still needed.
// Use system clock when the audio clock is not updated yet.
// As the audio clock can be updated discountinuously, the system clock is still needed.
if t > 5*int64(time.Second)/FPS {
// The previous time is too old.
// Let's force to sync the logical time with the OS clock.
sync = true
// Let's force to sync the game time with the system clock.
syncWithSystemClock = true
} else {
count = int(t * FPS / int64(time.Second))
}
@ -142,10 +144,10 @@ func Update() int {
}
frames += int64(count)
if sync {
logicalTime = n
if syncWithSystemClock {
gameTime = n
} else {
logicalTime += int64(count) * int64(time.Second) / FPS
gameTime += int64(count) * int64(time.Second) / FPS
}
updateFPS(n)