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) written += int64(n)
fs := written/int64(bytesPerFrame) - prevWritten/int64(bytesPerFrame) fs := written/int64(bytesPerFrame) - prevWritten/int64(bytesPerFrame)
for fs > 0 { for fs > 0 {
clock.ProceedPrimaryTimer() clock.ProceedAudioTimer()
fs-- fs--
} }
prevWritten = written prevWritten = written

View File

@ -12,6 +12,21 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // 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 package clock
import ( import (
@ -23,10 +38,11 @@ import (
const FPS = 60 const FPS = 60
var ( var (
primaryTime int64 audioTimeInFrames int64
lastPrimaryTime int64 lastAudioTimeInFrames int64
frames int64
logicalTime int64 frames int64
gameTime int64
currentFPS float64 currentFPS float64
lastFPSUpdated int64 lastFPSUpdated int64
@ -50,10 +66,10 @@ func RegisterPing(pingFunc func()) {
m.Unlock() m.Unlock()
} }
// ProceedPrimaryTimer increments the primary time by a frame. // ProceedAudioTimer increments the audio time by a frame.
func ProceedPrimaryTimer() { func ProceedAudioTimer() {
m.Lock() m.Lock()
primaryTime++ audioTimeInFrames++
m.Unlock() m.Unlock()
} }
@ -71,7 +87,7 @@ func updateFPS(now int64) {
} }
// Update updates the inner clock state and returns an integer value // 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 { func Update() int {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
@ -82,49 +98,35 @@ func Update() int {
ping() ping()
} }
// Initialize logicalTime if needed. // Initialize gameTime if needed.
if logicalTime == 0 { if gameTime == 0 {
logicalTime = n gameTime = n
} }
t := n - logicalTime t := n - gameTime
if t < 0 { if t < 0 {
return 0 return 0
} }
count := 0 count := 0
// Logical clock: syncWithSystemClock := false
// 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.
// When sync is true, the logical time is forced to sync with the system clock. if audioTimeInFrames > 0 && lastAudioTimeInFrames != audioTimeInFrames {
sync := false // If the audio clock is updated, use this.
if frames < audioTimeInFrames {
if primaryTime > 0 && lastPrimaryTime != primaryTime { count = int(audioTimeInFrames - frames)
// If the primary clock is updated, use this.
if frames < primaryTime {
count = int(primaryTime - frames)
} }
lastPrimaryTime = primaryTime lastAudioTimeInFrames = audioTimeInFrames
sync = true syncWithSystemClock = true
} else { } else {
// Use system clock when // Use system clock when the audio clock is not updated yet.
// 1) Inc() is not called, or // As the audio clock can be updated discountinuously, the system clock is still needed.
// 2) the primary clock is not updated yet.
// As the primary clock can be updated discountinuously, the system clock is still needed.
if t > 5*int64(time.Second)/FPS { if t > 5*int64(time.Second)/FPS {
// The previous time is too old. // The previous time is too old.
// Let's force to sync the logical time with the OS clock. // Let's force to sync the game time with the system clock.
sync = true syncWithSystemClock = true
} else { } else {
count = int(t * FPS / int64(time.Second)) count = int(t * FPS / int64(time.Second))
} }
@ -142,10 +144,10 @@ func Update() int {
} }
frames += int64(count) frames += int64(count)
if sync { if syncWithSystemClock {
logicalTime = n gameTime = n
} else { } else {
logicalTime += int64(count) * int64(time.Second) / FPS gameTime += int64(count) * int64(time.Second) / FPS
} }
updateFPS(n) updateFPS(n)