diff --git a/assets/Media/Prefabs/AppRoot.prefab b/assets/Media/Prefabs/AppRoot.prefab index 35f2b21..67afd45 100644 --- a/assets/Media/Prefabs/AppRoot.prefab +++ b/assets/Media/Prefabs/AppRoot.prefab @@ -23,16 +23,19 @@ }, { "__id__": 14 + }, + { + "__id__": 70 } ], "_active": true, "_components": [ { - "__id__": 70 + "__id__": 78 } ], "_prefab": { - "__id__": 72 + "__id__": 80 }, "_lpos": { "__type__": "cc.Vec3", @@ -1488,6 +1491,117 @@ }, "fileId": "f6cwwQmx9G2qaYOpNATP9o" }, + { + "__type__": "cc.Node", + "_objFlags": 0, + "_parent": { + "__id__": 1 + }, + "_prefab": { + "__id__": 71 + }, + "__editorExtras__": {} + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 70 + }, + "asset": { + "__uuid__": "f668086a-2bff-40eb-a029-dd891718441d", + "__expectedType__": "cc.Prefab" + }, + "fileId": "5da9o8mwlJl5XD861jGbYx", + "instance": { + "__id__": 72 + } + }, + { + "__type__": "cc.PrefabInstance", + "fileId": "56Xvr+wxdEcqGuJ2/9Drtp", + "prefabRootNode": { + "__id__": 1 + }, + "mountedChildren": [], + "mountedComponents": [], + "propertyOverrides": [ + { + "__id__": 73 + }, + { + "__id__": 75 + }, + { + "__id__": 76 + }, + { + "__id__": 77 + } + ], + "removedComponents": [] + }, + { + "__type__": "CCPropertyOverrideInfo", + "targetInfo": { + "__id__": 74 + }, + "propertyPath": [ + "_name" + ], + "value": "Y8" + }, + { + "__type__": "cc.TargetInfo", + "localID": [ + "5da9o8mwlJl5XD861jGbYx" + ] + }, + { + "__type__": "CCPropertyOverrideInfo", + "targetInfo": { + "__id__": 74 + }, + "propertyPath": [ + "_lpos" + ], + "value": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + } + }, + { + "__type__": "CCPropertyOverrideInfo", + "targetInfo": { + "__id__": 74 + }, + "propertyPath": [ + "_lrot" + ], + "value": { + "__type__": "cc.Quat", + "x": 0, + "y": 0, + "z": 0, + "w": 1 + } + }, + { + "__type__": "CCPropertyOverrideInfo", + "targetInfo": { + "__id__": 74 + }, + "propertyPath": [ + "_euler" + ], + "value": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + } + }, { "__type__": "4943dSvt9FBvLizJ1HhFOzg", "_name": "", @@ -1497,7 +1611,7 @@ }, "_enabled": true, "__prefab": { - "__id__": 71 + "__id__": 79 }, "audio": { "__id__": 11 @@ -1523,6 +1637,7 @@ "screenFader": { "__id__": 55 }, + "y8": null, "_id": "" }, { @@ -1537,6 +1652,38 @@ "asset": { "__id__": 0 }, - "fileId": "f6TS0IBq9EGpNVBB7WXcF6" + "fileId": "f6TS0IBq9EGpNVBB7WXcF6", + "targetOverrides": [ + { + "__id__": 81 + } + ], + "nestedPrefabInstanceRoots": [ + { + "__id__": 70 + } + ] + }, + { + "__type__": "cc.TargetOverrideInfo", + "source": { + "__id__": 78 + }, + "sourceInfo": null, + "propertyPath": [ + "y8" + ], + "target": { + "__id__": 70 + }, + "targetInfo": { + "__id__": 82 + } + }, + { + "__type__": "cc.TargetInfo", + "localID": [ + "9cOBr9gAFNWbvsaSX5dfaa" + ] } ] \ No newline at end of file diff --git a/assets/Scripts/AppRoot/Analytics.ts b/assets/Scripts/AppRoot/Analytics.ts new file mode 100644 index 0000000..be7d55c --- /dev/null +++ b/assets/Scripts/AppRoot/Analytics.ts @@ -0,0 +1,44 @@ +import { Y8 } from "../../Plugins/Y8/Scripts/Y8"; + +export class Analytics { + private totalTime = 0; + private minutesInGame = -1; // Track the 0 minute as well + private gamesPerSession = 0; + + public constructor(private y8: Y8) {} + + public update(deltaTime: number): void { + this.totalTime += deltaTime; + this.trySendTotalTime(); + } + + public gameStart(): void { + this.y8.sendCustomEvent(EventName.GAMES_PER_SESSION, ++this.gamesPerSession); + } + + public gameEnd(time: number): void { + this.y8.sendCustomEvent(EventName.GAME_TIME, Math.floor(time)); + } + + public gameExit(time: number): void { + this.y8.sendCustomEvent(EventName.GAME_EXIT, Math.floor(time)); + } + + public goldPerRun(goldEarned: number): void { + this.y8.sendCustomEvent(EventName.GOLD_PER_RUN, Math.floor(goldEarned)); + } + + private trySendTotalTime(): void { + if (this.minutesInGame < Math.floor(this.totalTime / 60)) { + this.y8.sendCustomEvent(EventName.TOTAL_TIME, ++this.minutesInGame); + } + } +} + +enum EventName { + TOTAL_TIME = "Minutes_total", + GOLD_PER_RUN = "Gold_per_run", + GAMES_PER_SESSION = "Games_per_session", + GAME_TIME = "Game_time_seconds", + GAME_EXIT = "Game_exit" +} diff --git a/assets/Scripts/AppRoot/Analytics.ts.meta b/assets/Scripts/AppRoot/Analytics.ts.meta new file mode 100644 index 0000000..4ed4d13 --- /dev/null +++ b/assets/Scripts/AppRoot/Analytics.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "58a3e586-6c96-4f84-8682-7a73b1b72b9f", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/Scripts/AppRoot/AppRoot.ts b/assets/Scripts/AppRoot/AppRoot.ts index 3a6189d..2d25382 100644 --- a/assets/Scripts/AppRoot/AppRoot.ts +++ b/assets/Scripts/AppRoot/AppRoot.ts @@ -7,6 +7,8 @@ import { AudioPlayer } from "../Services/AudioPlayer/AudioPlayer"; import { SaveSystem } from "./SaveSystem"; import { ModalWindowManager } from "../Services/ModalWindowSystem/ModalWindowManager"; import { OpenCloseAnimator } from "../Utils/OpenCloseAnimator"; +import { Y8 } from "../../Plugins/Y8/Scripts/Y8"; +import { Analytics } from "./Analytics"; const { ccclass, property } = _decorator; @ccclass("AppRoot") @@ -18,12 +20,14 @@ export class AppRoot extends Component { @property(Camera) private mainCamera: Camera; @property(ModalWindowManager) private modalWindowManager: ModalWindowManager; @property(OpenCloseAnimator) private screenFader: OpenCloseAnimator; + @property(Y8) private y8: Y8; private static instance: AppRoot; private saveSystem: SaveSystem; private liveUserData: UserData; private gameAssets: GameAssets; + private analytics: Analytics; public static get Instance(): AppRoot { return this.instance; @@ -61,6 +65,14 @@ export class AppRoot extends Component { return this.screenFader; } + public get Y8(): Y8 { + return this.y8; + } + + public get Analytics(): Analytics { + return this.analytics; + } + public saveUserData(): void { this.saveSystem.save(this.liveUserData); } @@ -75,7 +87,11 @@ export class AppRoot extends Component { } } - private init(): void { + public update(deltaTime: number): void { + if (this.analytics) this.analytics.update(deltaTime); + } + + private async init(): Promise { this.saveSystem = new SaveSystem(); this.liveUserData = this.saveSystem.load(); @@ -88,5 +104,9 @@ export class AppRoot extends Component { this.screenFader.init(); this.screenFader.node.active = false; + + await this.y8.init(); + + this.analytics = new Analytics(this.y8); } } diff --git a/assets/Scripts/Game/Game.ts b/assets/Scripts/Game/Game.ts index 2efdc9a..6bd90d1 100644 --- a/assets/Scripts/Game/Game.ts +++ b/assets/Scripts/Game/Game.ts @@ -1,4 +1,4 @@ -import { Canvas, Component, KeyCode, Vec2, _decorator, Node } from "cc"; +import { Canvas, Component, KeyCode, Vec2, _decorator, Node, approx } from "cc"; import { AppRoot } from "../AppRoot/AppRoot"; import { requireAppRootAsync } from "../AppRoot/AppRootUtils"; import { delay } from "../Services/Utils/AsyncUtils"; @@ -81,6 +81,8 @@ export class Game extends Component { public async play(userData: UserData, settings: GameSettings, translationData: TranslationData, testValues?: TestValues): Promise { await this.setup(userData, settings, translationData, testValues); + AppRoot.Instance.Analytics.gameStart(); + this.gamePauser.resume(); this.blackScreen.active = false; AppRoot.Instance.ScreenFader.playClose(); @@ -92,7 +94,12 @@ export class Game extends Component { this.gameResult.score = this.timeAlive; if (!this.gameResult.hasExitManually) { + AppRoot.Instance.Analytics.goldPerRun(this.gameResult.goldCoins); + AppRoot.Instance.Analytics.gameEnd(this.gameResult.score); + await delay(2000); + } else { + AppRoot.Instance.Analytics.gameExit(this.timeAlive); } return this.gameResult;