Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

M2-8255: fix timing mismatch #900

Merged
merged 8 commits into from
Nov 26, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 85 additions & 52 deletions ios/FlankerNativeComponents/GameManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,16 @@ enum TypeTimeStamps {
}

protocol GameManagerProtocol: AnyObject {
func updateText(text: String, color: UIColor, font: UIFont, isStart: Bool, typeTime: TypeTimeStamps)
func updateText(
text: String, color: UIColor, font: UIFont, isStart: Bool, typeTime: TypeTimeStamps)
func updateFixations(image: URL?, isStart: Bool, typeTime: TypeTimeStamps)
func updateTime(time: String)
func setEnableButton(isEnable: Bool)
func updateTitleButton(left: String?, right: String?, leftImage: URL?, rightImage: URL?, countButton: Int)
func resultTest(avrgTime: Int?, procentCorrect: Int?, data: FlankerModel?, dataArray: [FlankerModel]?, isShowResults: Bool, minAccuracy: Int)
func updateTitleButton(
left: String?, right: String?, leftImage: URL?, rightImage: URL?, countButton: Int)
func resultTest(
avrgTime: Int?, procentCorrect: Int?, data: FlankerModel?, dataArray: [FlankerModel]?,
isShowResults: Bool, minAccuracy: Int)
}

class GameManager {
Expand Down Expand Up @@ -78,11 +82,11 @@ class GameManager {
weak var delegate: GameManagerProtocol?

private let bootTime: Double = {
let uptime = CACurrentMediaTime()
let nowTime = Date().timeIntervalSince1970
return nowTime - uptime
}()
let uptime = CACurrentMediaTime()
let nowTime = Date().timeIntervalSince1970
return nowTime - uptime
}()

func startGame(timeSpeed: Float, isShowAnswers: Bool, countGame: Int) {
countAllGame = countGame
timeSpeedGame = TimeInterval(timeSpeed)
Expand Down Expand Up @@ -115,7 +119,7 @@ class GameManager {
case .fixations:
startFixationsTimestamp = time
case .trial:
break
break
case .feedback:
startFeedbackTimestamp = time
case .response:
Expand All @@ -137,14 +141,15 @@ class GameManager {

func checkedAnswer(button: SelectedButton) {
guard !hasRespondedInCurrentTrial else { return }
guard let startTrialTimestamp = startTrialTimestamp else { return }
ChaconC marked this conversation as resolved.
Show resolved Hide resolved
hasRespondedInCurrentTrial = true
respondTouchButton = bootTime + CACurrentMediaTime()
invalidateTimers()

delegate?.setEnableButton(isEnable: false)

guard let gameParameters = gameParameters else { return }
guard let startTrialTimestamp = startTrialTimestamp else { return }
guard countTest >= 0 && countTest < gameParameters.trials.count else { return }
var resultTime = (respondTouchButton! - startTrialTimestamp) * 1000

arrayTimes.append(Int(resultTime))
Expand All @@ -155,31 +160,39 @@ class GameManager {
startFeedbackTimestamp = bootTime + CACurrentMediaTime()

let correctChoice = gameParameters.trials[countTest].correctChoice
let isCorrect = (button == .left && correctChoice == 0) || (button == .right && correctChoice == 1)
let isCorrect =
(button == .left && correctChoice == 0) || (button == .right && correctChoice == 1)
if isCorrect {
correctAnswers += 1
}

let buttonPressed = (button == .left) ? "0" : "1"
let model = FlankerModel(rt: resultTime,
stimulus: text,
button_pressed: buttonPressed,
image_time: endTrialTimestamp! * 1000,
correct: isCorrect,
start_timestamp: 0,
tag: Constants.tag,
trial_index: countTest + 1,
start_time: startTrialTimestamp * 1000,
response_touch_timestamp: respondTouchButton! * 1000)
let model = FlankerModel(
rt: resultTime,
stimulus: text,
button_pressed: buttonPressed,
image_time: endTrialTimestamp! * 1000,
correct: isCorrect,
start_timestamp: 0,
tag: Constants.tag,
trial_index: countTest + 1,
start_time: startTrialTimestamp * 1000,
response_touch_timestamp: respondTouchButton! * 1000)

resultManager.addStepData(data: model)
delegate?.resultTest(avrgTime: nil, procentCorrect: nil, data: model, dataArray: nil, isShowResults: false, minAccuracy: gameParameters.minimumAccuracy)
delegate?.resultTest(
avrgTime: nil, procentCorrect: nil, data: model, dataArray: nil, isShowResults: false,
minAccuracy: gameParameters.minimumAccuracy)

if gameParameters.showFeedback {
let feedbackText = isCorrect ? Constants.correctText : Constants.inCorrectText
let feedbackColor = isCorrect ? Constants.greenColor : Constants.redColor
delegate?.updateText(text: feedbackText, color: feedbackColor, font: Constants.smallFont, isStart: false, typeTime: .feedback)
let timer = Timer(timeInterval: Constants.lowTimeInterval, target: self, selector: #selector(setDefaultText), userInfo: nil, repeats: false)
delegate?.updateText(
text: feedbackText, color: feedbackColor, font: Constants.smallFont, isStart: false,
typeTime: .feedback)
let timer = Timer(
timeInterval: Constants.lowTimeInterval, target: self, selector: #selector(setDefaultText),
userInfo: nil, repeats: false)
RunLoop.main.add(timer, forMode: .common)
} else {
setDefaultText(isFirst: false)
Expand All @@ -189,9 +202,10 @@ class GameManager {
@objc func setDefaultText(isFirst: Bool) {
guard let gameParameters = gameParameters else { return }

hasRespondedInCurrentTrial = false
delegate?.setEnableButton(isEnable: false)

hasRespondedInCurrentTrial = false

if !isFirst {
endFeedbackTimestamp = bootTime + CACurrentMediaTime()
countTest += 1
Expand All @@ -208,12 +222,17 @@ class GameManager {

if gameParameters.showFixation {
startFixationsTimestamp = bootTime + CACurrentMediaTime()
if let image = URL(string: gameParameters.fixation), gameParameters.fixation.contains("https") {
if let image = URL(string: gameParameters.fixation), gameParameters.fixation.contains("https")
{
delegate?.updateFixations(image: image, isStart: true, typeTime: .fixations)
} else {
delegate?.updateText(text: gameParameters.fixation, color: .black, font: Constants.bigFont, isStart: true, typeTime: .fixations)
delegate?.updateText(
text: gameParameters.fixation, color: .black, font: Constants.bigFont, isStart: true,
typeTime: .fixations)
}
timerSetText = Timer(timeInterval: gameParameters.fixationDuration / 1000, target: self, selector: #selector(setText), userInfo: nil, repeats: false)
timerSetText = Timer(
timeInterval: gameParameters.fixationDuration / 1000, target: self,
selector: #selector(setText), userInfo: nil, repeats: false)
RunLoop.main.add(timerSetText!, forMode: .common)
} else {
setText()
Expand All @@ -223,27 +242,33 @@ class GameManager {
@objc func setText() {
guard let gameParameters = gameParameters else { return }
guard countTest < gameParameters.trials.count else {
handleEndOfGame()
return
handleEndOfGame()
return
}

endFixationsTimestamp = bootTime + CACurrentMediaTime()

startTrialTimestamp = bootTime + CACurrentMediaTime()

hasRespondedInCurrentTrial = false

text = gameParameters.trials[countTest].stimulus.en

if let image = URL(string: text), text.contains("https") {
delegate?.updateFixations(image: image, isStart: true, typeTime: .trial)
} else {
delegate?.updateText(text: text, color: .black, font: Constants.bigFont, isStart: true, typeTime: .trial)
delegate?.updateText(
text: text, color: .black, font: Constants.bigFont, isStart: true, typeTime: .trial)
}

DispatchQueue.main.asyncAfter(deadline: .now()) {
self.delegate?.setEnableButton(isEnable: true)
self.timeResponse = Timer(timeInterval: gameParameters.trialDuration / 1000, target: self, selector: #selector(self.timeResponseFailed), userInfo: nil, repeats: false)
RunLoop.main.add(self.timeResponse!, forMode: .common)
}
delegate?.setEnableButton(isEnable: true)

timeResponse = Timer(
timeInterval: gameParameters.trialDuration / 1000,
target: self,
selector: #selector(timeResponseFailed),
userInfo: nil,
repeats: false)
RunLoop.main.add(timeResponse!, forMode: .common)
}

@objc func timeResponseFailed() {
Expand All @@ -256,27 +281,34 @@ class GameManager {
startFeedbackTimestamp = bootTime + CACurrentMediaTime()

if gameParameters.showFeedback {
delegate?.updateText(text: Constants.timeRespondText, color: .black, font: Constants.smallFont, isStart: false, typeTime: .feedback)
delegate?.updateText(
text: Constants.timeRespondText, color: .black, font: Constants.smallFont, isStart: false,
typeTime: .feedback)
}

guard let startTrialTimestamp = startTrialTimestamp else { return }

let model = FlankerModel(rt: 0.0,
stimulus: text,
button_pressed: nil,
image_time: endTrialTimestamp! * 1000, // має намалювати
correct: false,
start_timestamp: 0, // вже намальовано
tag: Constants.tag,
trial_index: countTest + 1,
start_time: startTrialTimestamp * 1000,
response_touch_timestamp: 0)
let model = FlankerModel(
rt: 0.0,
stimulus: text,
button_pressed: nil,
image_time: endTrialTimestamp! * 1000, // має намалювати
correct: false,
start_timestamp: 0, // вже намальовано
tag: Constants.tag,
trial_index: countTest + 1,
start_time: startTrialTimestamp * 1000,
response_touch_timestamp: 0)

resultManager.addStepData(data: model)
delegate?.resultTest(avrgTime: nil, procentCorrect: nil, data: model, dataArray: nil,isShowResults: gameParameters.showResults, minAccuracy: gameParameters.minimumAccuracy)
delegate?.resultTest(
avrgTime: nil, procentCorrect: nil, data: model, dataArray: nil,
isShowResults: gameParameters.showResults, minAccuracy: gameParameters.minimumAccuracy)

if gameParameters.showFeedback {
let timer = Timer(timeInterval: Constants.lowTimeInterval, target: self, selector: #selector(setDefaultText), userInfo: nil, repeats: false)
let timer = Timer(
timeInterval: Constants.lowTimeInterval, target: self, selector: #selector(setDefaultText),
userInfo: nil, repeats: false)
RunLoop.main.add(timer, forMode: .common)
} else {
setDefaultText(isFirst: false)
Expand Down Expand Up @@ -314,6 +346,7 @@ class GameManager {
countTest = -1
correctAnswers = 0
arrayTimes = []
hasRespondedInCurrentTrial = false
invalidateTimers()
}

Expand All @@ -323,8 +356,8 @@ class GameManager {
}
}

private extension GameManager {
func updateButtonTitle() {
extension GameManager {
fileprivate func updateButtonTitle() {
guard let gameParameters = gameParameters else { return }
guard countTest < gameParameters.trials.count else { return }

Expand Down
Loading