mobile-gaming-analytics-kullanici-davranislarini-anlama

Mobile Gaming Analytics: Kullanıcı Davranışlarını Anlama

İçindekiler

Mobil oyun geliştirmede başarı, kullanıcı davranışlarını doğru analiz etmek ve bu analizler doğrultusunda kararlar almaktan geçer. Chipode olarak, Sudoku uygulamamızda kullanıcı deneyimini sürekli iyileştirmek için analytics verilerini nasıl topladığımızı ve kullandığımızı bu yazıda paylaşacağız.

Analytics Altyapısı

1- Firebase Analytics Entegrasyonu

				
					dart
class AnalyticsService {
  final FirebaseAnalytics _analytics;
  
  AnalyticsService() : _analytics = FirebaseAnalytics.instance;
  
  Future<void> logGameStart({
    required String difficulty,
    required bool isDaily,
  }) async {
    await _analytics.logEvent(
      name: 'game_start',
      parameters: {
        'difficulty': difficulty,
        'game_type': isDaily ? 'daily' : 'regular',
        'timestamp': DateTime.now().toIso8601String(),
      },
    );
  }
  
  Future<void> logGameComplete({
    required String difficulty,
    required int timeSpent,
    required int score,
    required bool usedHints,
  }) async {
    await _analytics.logEvent(
      name: 'game_complete',
      parameters: {
        'difficulty': difficulty,
        'time_spent': timeSpent,
        'score': score,
        'used_hints': usedHints,
      },
    );
  }
}


				
			

2- Custom Event Tracking

				
					dart
class GameAnalytics {
  final AnalyticsService _analytics;
  final UserMetricsRepository _metrics;
  
  Future<void> trackCellInput({
    required int row,
    required int col,
    required int value,
    required bool isNote,
    required Duration timeToDecide,
  }) async {
    await _analytics.logEvent(
      name: 'cell_input',
      parameters: {
        'position': '${row}x${col}',
        'value': value,
        'is_note': isNote,
        'decision_time': timeToDecide.inSeconds,
      },
    );
  }
  
  Future<void> trackHintUsage({
    required HintType type,
    required int remainingHints,
    required GameProgress progress,
  }) async {
    await _analytics.logEvent(
      name: 'hint_used',
      parameters: {
        'hint_type': type.toString(),
        'remaining_hints': remainingHints,
        'board_completion': progress.completionPercentage,
        'stuck_duration': progress.timeSinceLastMove.inMinutes,
      },
    );
  }
}



				
			

Kullanıcı Segmentasyonu

1- Oyuncu Profili Analizi

				
					dart
class PlayerProfileAnalyzer {
  PlayerSegment categorizePlayer(UserMetrics metrics) {
    final skillLevel = _calculateSkillLevel(metrics);
    final engagement = _calculateEngagement(metrics);
    final monetization = _analyzeMonetization(metrics);
    
    return PlayerSegment(
      skillLevel: skillLevel,
      engagementLevel: engagement,
      monetizationTier: monetization,
    );
  }
  
  SkillLevel _calculateSkillLevel(UserMetrics metrics) {
    final avgTimePerPuzzle = metrics.totalPlayTime.inMinutes / 
                            metrics.completedPuzzles;
    
    final difficultyScore = metrics.completedByDifficulty.entries
      .map((e) => e.key.weight * e.value)
      .reduce((a, b) => a + b);
      
    if (avgTimePerPuzzle < 5 && difficultyScore > 100) {
      return SkillLevel.expert;
    } else if (avgTimePerPuzzle < 10 && difficultyScore > 50) {
      return SkillLevel.advanced;
    }
    return SkillLevel.beginner;
  }
  
  // Diğer analiz metodları...
}

				
			

2- Cohort Analizi

				
					dart
class CohortAnalysis {
  Future<Map<String, RetentionMetrics>> analyzeRetention(
    DateTime startDate,
    DateTime endDate,
  ) async {
    final cohorts = await _groupUsersByCohort(startDate, endDate);
    final metrics = <String, RetentionMetrics>{};
    
    for (var cohort in cohorts.entries) {
      metrics[cohort.key] = await _calculateRetention(
        users: cohort.value,
        startDate: cohort.key,
      );
    }
    
    return metrics;
  }
  
  Future<RetentionMetrics> _calculateRetention({
    required List<String> users,
    required DateTime startDate,
  }) async {
    final day1 = await _getActiveUsers(users, startDate.add(Duration(days: 1)));
    final day7 = await _getActiveUsers(users, startDate.add(Duration(days: 7)));
    final day30 = await _getActiveUsers(users, startDate.add(Duration(days: 30)));
    
    return RetentionMetrics(
      totalUsers: users.length,
      day1Retention: day1.length / users.length,
      day7Retention: day7.length / users.length,
      day30Retention: day30.length / users.length,
    );
  }
}


				
			

Performans Metrikleri

1- Oyun Performansı Takibi

				
					dart
class GamePerformanceTracker {
  final PerformanceCollector _collector;
  
  void trackFrameTime(Duration frameTime) {
    _collector.addMetric(
      name: 'frame_time',
      value: frameTime.inMicroseconds,
      labels: {'screen': 'game_board'},
    );
  }
  
  void trackLoadTime({
    required String difficulty,
    required Duration duration,
  }) {
    _collector.addMetric(
      name: 'puzzle_load_time',
      value: duration.inMilliseconds,
      labels: {
        'difficulty': difficulty,
        'cache_status': duration.inSeconds > 1 ? 'miss' : 'hit',
      },
    );
  }
  
  void trackMemoryUsage() {
    if (!kReleaseMode) return;
    
    final usage = ProcessInfo.currentRss;
    _collector.addMetric(
      name: 'memory_usage',
      value: usage,
      labels: {'type': 'rss'},
    );
  }
}


				
			

2- Ağ Performansı İzleme

				
					dart
class NetworkPerformanceMonitor {
  final _metrics = <String, List<Duration>>{};
  
  void trackApiCall(String endpoint, Duration duration) {
    _metrics.putIfAbsent(endpoint, () => []).add(duration);
    
    if (_metrics[endpoint]!.length >= 100) {
      _calculateAndReportMetrics(endpoint);
    }
  }
  
  void _calculateAndReportMetrics(String endpoint) {
    final durations = _metrics[endpoint]!;
    durations.sort();
    
    final p50 = durations[durations.length ~/ 2];
    final p90 = durations[(durations.length * 0.9).floor()];
    final p99 = durations[(durations.length * 0.99).floor()];
    
    _reportLatencyMetrics(endpoint, {
      'p50': p50.inMilliseconds,
      'p90': p90.inMilliseconds,
      'p99': p99.inMilliseconds,
    });
    
    _metrics[endpoint]?.clear();
  }
}


				
			

A/B Testing

1- Test Konfigürasyonu

				
					dart
class ABTestingService {
  final RemoteConfig _config;
  final AnalyticsService _analytics;
  
  Future<ExperimentVariant> getVariant(String experiment) async {
    final variantId = _config.getString('exp_${experiment}_variant');
    return ExperimentVariant.fromId(variantId);
  }
  
  Future<void> trackExposure({
    required String experiment,
    required String variant,
  }) async {
    await _analytics.logEvent(
      name: 'experiment_exposure',
      parameters: {
        'experiment': experiment,
        'variant': variant,
      },
    );
  }
  
  Future<void> trackConversion({
    required String experiment,
    required String variant,
    required String goal,
  }) async {
    await _analytics.logEvent(
      name: 'experiment_conversion',
      parameters: {
        'experiment': experiment,
        'variant': variant,
        'goal': goal,
      },
    );
  }
}



				
			

2- Test İmplementasyonu

				
					dart
class DifficultyExperiment extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<ABTestingService>(
      builder: (context, abTest, child) {
        return FutureBuilder<ExperimentVariant>(
          future: abTest.getVariant('difficulty_screens'),
          builder: (context, snapshot) {
            if (!snapshot.hasData) {
              return DefaultDifficultyScreen();
            }
            
            final variant = snapshot.data!;
            abTest.trackExposure(
              experiment: 'difficulty_screens',
              variant: variant.id,
            );
            
            switch (variant) {
              case ExperimentVariant.control:
                return DefaultDifficultyScreen();
              case ExperimentVariant.test:
                return NewDifficultyScreen();
              default:
                return DefaultDifficultyScreen();
            }
          },
        );
      },
    );
  }
}


				
			

Veri Görselleştirme

1- Dashboard Widgets

				
					dart
class MetricsDashboard extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GridView.count(
      crossAxisCount: 2,
      children: [
        RetentionChart(),
        EngagementMetrics(),
        DifficultyDistribution(),
        TimeSpentAnalysis(),
      ],
    );
  }
}

class RetentionChart extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<AnalyticsRepository>(
      builder: (context, repository, child) {
        return FutureBuilder<RetentionData>(
          future: repository.getRetentionData(),
          builder: (context, snapshot) {
            if (!snapshot.hasData) {
              return LoadingIndicator();
            }
            
            return LineChart(
              data: snapshot.data!.toChartData(),
              xAxis: ChartAxis(label: 'Gün'),
              yAxis: ChartAxis(
                label: 'Kullanıcı Oranı',
                format: percentageFormat,
              ),
            );
          },
        );
      },
    );
  }
}


				
			

Machine Learning Entegrasyonu

1- Zorluk Seviyesi Önerisi

				
					dart
class DifficultyRecommender {
  final MLModel _model;
  
  Future<GameDifficulty> recommendDifficulty(UserMetrics metrics) async {
    final features = _prepareFeatures(metrics);
    final prediction = await _model.predict(features);
    
    return _difficultyFromPrediction(prediction);
  }
  
  Map<String, dynamic> _prepareFeatures(UserMetrics metrics) {
    return {
      'avg_completion_time': metrics.averageCompletionTime.inMinutes,
      'success_rate': metrics.successRate,
      'hints_used_ratio': metrics.hintsUsedRatio,
      'highest_difficulty_completed': metrics.highestDifficultyCompleted,
      'total_games_played': metrics.totalGamesPlayed,
    };
  }
  
  GameDifficulty _difficultyFromPrediction(double prediction) {
    if (prediction > 0.8) return GameDifficulty.expert;
    if (prediction > 0.6) return GameDifficulty.hard;
    if (prediction > 0.4) return GameDifficulty.medium;
    return GameDifficulty.easy;
  }
}



				
			

Sonuç

Analytics verilerinin doğru analizi ve kullanımı sayesinde:

1. Kullanıcı deneyimini sürekli iyileştirebiliyoruz
2. Oyun zorluğunu kullanıcılara göre optimize edebiliyoruz
3. Performans sorunlarını proaktif olarak tespit edebiliyoruz
4. A/B testleri ile yeni özellikleri güvenle test edebiliyoruz
5. Veri odaklı kararlar alabiliyoruz

İleriye Dönük Planlar

– Gerçek zamanlı analytics
– Gelişmiş anomali tespiti
– Kişiselleştirilmiş oyun deneyimi
– Churn prediction modeli
– Sosyal özelliklerin analizi

Kaynaklar

Twitter
LinkedIn
Diğer Yazılar
İletişim

Chipode Uygulamaları

loading...
Google Play Store
loading...
Apple Store