Game Framework
Examples

Flutter Example App

Explore the complete Flutter example application that demonstrates all Game Framework features including engine initialization, bidirectional communication, lifecycle management, and UI patterns.

Overview

The example app showcases:

  • Engine Initialization - Unity and Unreal Engine plugin setup
  • Bidirectional Communication - Flutter ↔ Engine messaging
  • Lifecycle Management - Pause/resume/destroy handling
  • UI Overlay - Flutter UI on top of game view
  • Event Logging - Real-time message stream monitoring
  • Streaming Example - Content downloading and streaming
  • Platform View Modes - Android platform view options

This is a complete, production-ready example you can use as a template for your own projects!

Getting Started

Clone the Repository

git clone https://github.com/xraph/gameframework.git
cd gameframework/example

Install Dependencies

flutter pub get

Run the Example

# Run on connected device
flutter run

# Run on specific platform
flutter run -d android
flutter run -d ios
flutter run -d macos

App Structure

Main Entry Point

import 'package:flutter/material.dart';
import 'package:gameframework/gameframework.dart';
import 'package:gameframework_unity/gameframework_unity.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize engine plugins
  UnityEnginePlugin.initialize();
  
  runApp(const MyApp());
}

Home Screen

The home screen provides navigation to different examples:

  • Unity Example - Interactive rotating cube demo
  • Unreal Example - Unreal Engine integration (coming soon)
  • Streaming Example - Content streaming demonstration

Unity Example Screen

Features Demonstrated

The Unity example screen includes:

  1. Interactive Controls

    • Speed slider (-180° to 180°/second)
    • Axis selector (X, Y, Z, All)
    • Control buttons (Reset, Get State, Random Color)
  2. Real-Time Display

    • Current speed and RPM
    • Rotation axis
    • Communication direction
    • Event log
  3. UI Patterns

    • Expandable control panel
    • Mini HUD for quick info
    • Dark theme with transparency
    • Smooth animations

Code Structure

class UnityExampleScreen extends StatefulWidget {
  @override
  State<UnityExampleScreen> createState() => _UnityExampleScreenState();
}

class _UnityExampleScreenState extends State<UnityExampleScreen> {
  GameEngineController? _controller;
  double _targetSpeed = 50.0;
  String _rotationAxis = 'Y';
  List<String> _logs = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          // Unity view fills the entire screen
          GameWidget(
            engineType: GameEngineType.unity,
            config: GameEngineConfig(
              runImmediately: true,
            ),
            onEngineCreated: _onEngineCreated,
            onMessage: _onMessage,
          ),
          
          // Flutter UI overlay
          _buildControlPanel(),
          _buildMiniHud(),
        ],
      ),
    );
  }

  void _onEngineCreated(GameEngineController controller) {
    setState(() {
      _controller = controller;
      _isReady = true;
    });
    _addLog('✓ Engine ready');
  }

  void _onMessage(GameEngineMessage message) {
    _addLog('← ${message.method}: ${message.data}');
    
    // Parse message and update UI
    if (message.method == 'onStateUpdate') {
      final state = jsonDecode(message.data);
      setState(() {
        _currentSpeed = state['speed'] ?? 0;
        _currentRpm = state['rpm'] ?? 0;
      });
    }
  }
}

Control Panel UI

Expandable Panel

Widget _buildControlPanel() {
  return Positioned(
    bottom: 0,
    left: 0,
    right: 0,
    child: AnimatedBuilder(
      animation: _panelAnimation,
      builder: (context, child) {
        return Container(
          height: _isPanelExpanded ? 400 : 80,
          decoration: BoxDecoration(
            color: Colors.black.withOpacity(0.8),
            borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
          ),
          child: Column(
            children: [
              // Panel header with toggle button
              _buildPanelHeader(),
              
              // Panel content (expanded)
              if (_isPanelExpanded)
                Expanded(child: _buildPanelContent()),
            ],
          ),
        );
      },
    ),
  );
}

Speed Control

Widget _buildSpeedControl() {
  return Column(
    children: [
      Text('Speed: ${_targetSpeed.toStringAsFixed(0)}°/s'),
      Slider(
        value: _targetSpeed,
        min: -180,
        max: 180,
        onChanged: (value) {
          setState(() => _targetSpeed = value);
        },
        onChangeEnd: (value) {
          _setSpeed(value);
        },
      ),
    ],
  );
}

void _setSpeed(double speed) {
  _controller?.sendJsonMessage('GameFrameworkDemo', 'setSpeed', {
    'speed': speed,
  });
  _addLog('→ setSpeed: $speed');
}

Axis Selector

Widget _buildAxisSelector() {
  return Row(
    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
    children: ['X', 'Y', 'Z', 'All'].map((axis) {
      return ElevatedButton(
        onPressed: () => _setAxis(axis),
        style: ElevatedButton.styleFrom(
          backgroundColor: _rotationAxis == axis 
            ? Colors.blue 
            : Colors.grey[800],
        ),
        child: Text(axis),
      );
    }).toList(),
  );
}

void _setAxis(String axis) {
  setState(() => _rotationAxis = axis);
  _controller?.sendJsonMessage('GameFrameworkDemo', 'setAxis', {
    'axis': axis,
  });
  _addLog('→ setAxis: $axis');
}

Event Logging

final List<String> _logs = [];
final int _maxLogs = 100;

void _addLog(String message) {
  setState(() {
    _logs.insert(0, '${_formatTime()} $message');
    if (_logs.length > _maxLogs) {
      _logs.removeLast();
    }
  });
}

Widget _buildEventLog() {
  return Container(
    height: 200,
    decoration: BoxDecoration(
      color: Colors.black.withOpacity(0.9),
      borderRadius: BorderRadius.circular(8),
    ),
    child: ListView.builder(
      reverse: true,
      itemCount: _logs.length,
      itemBuilder: (context, index) {
        final log = _logs[index];
        return Padding(
          padding: EdgeInsets.symmetric(horizontal: 12, vertical: 4),
          child: Text(
            log,
            style: TextStyle(
              fontFamily: 'monospace',
              fontSize: 11,
              color: _getLogColor(log),
            ),
          ),
        );
      },
    ),
  );
}

Color _getLogColor(String log) {
  if (log.contains('←')) return Colors.green;
  if (log.contains('→')) return Colors.orange;
  if (log.contains('✓')) return Colors.lightBlue;
  if (log.contains('✗')) return Colors.red;
  return Colors.grey;
}

Mini HUD

Widget _buildMiniHud() {
  if (_isPanelExpanded || !_showMiniHud) return SizedBox.shrink();
  
  return Positioned(
    top: 100,
    right: 16,
    child: Container(
      padding: EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: Colors.black.withOpacity(0.7),
        borderRadius: BorderRadius.circular(8),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('Speed: ${_currentSpeed.toStringAsFixed(0)}°/s',
            style: TextStyle(color: Colors.white, fontSize: 12)),
          Text('RPM: ${_currentRpm.toStringAsFixed(1)}',
            style: TextStyle(color: Colors.white70, fontSize: 11)),
          Text('Axis: $_rotationAxis',
            style: TextStyle(color: Colors.white70, fontSize: 11)),
        ],
      ),
    ),
  );
}

Lifecycle Management

@override
void dispose() {
  // Clean up controller when screen is disposed
  _controller?.dispose();
  _panelAnimationController.dispose();
  super.dispose();
}

void _pauseEngine() {
  _controller?.pause();
  _addLog('⏸ Engine paused');
}

void _resumeEngine() {
  _controller?.resume();
  _addLog('▶ Engine resumed');
}

Streaming Example

The streaming example demonstrates content downloading and asset streaming:

class StreamingExampleScreen extends StatefulWidget {
  @override
  State<StreamingExampleScreen> createState() => _StreamingExampleScreenState();
}

class _StreamingExampleScreenState extends State<StreamingExampleScreen> {
  double _downloadProgress = 0.0;
  bool _isDownloading = false;

  Future<void> _downloadAsset(String assetUrl) async {
    setState(() => _isDownloading = true);
    
    try {
      final response = await http.get(Uri.parse(assetUrl));
      final bytes = response.bodyBytes;
      
      // Send to Unity
      await _controller?.sendBinaryMessage(
        'AssetManager',
        'loadAsset',
        bytes,
      );
      
      setState(() => _isDownloading = false);
    } catch (e) {
      _showError('Download failed: $e');
      setState(() => _isDownloading = false);
    }
  }
}

Platform-Specific Features

Android Platform View Modes

// Hybrid Composition (default, better compatibility)
config: GameEngineConfig(
  platformViewType: PlatformViewType.hybridComposition,
)

// Virtual Display (better performance)
config: GameEngineConfig(
  platformViewType: PlatformViewType.virtualDisplay,
)

What You'll Learn

From the example app, you'll learn:

  • ✅ Complete app structure and organization
  • ✅ Engine initialization and setup
  • ✅ Bidirectional communication patterns
  • ✅ UI overlay and interaction design
  • ✅ Event logging and debugging
  • ✅ Lifecycle management
  • ✅ State management
  • ✅ Error handling
  • ✅ Platform-specific configurations

The example app uses production-ready patterns and best practices you can apply to your own projects.

Running on Different Platforms

Android

flutter run -d android

# Or build APK
flutter build apk

iOS

flutter run -d ios

# Or build IPA
flutter build ios

macOS

flutter run -d macos

# Or build app
flutter build macos

Customization

Modify Unity Integration

  1. Open Unity project in example/unity/demo/
  2. Edit GameFrameworkDemo.cs script
  3. Export and sync:
cd example
game export unity --platform android
game sync unity --platform android

Extend the Example

Add your own examples by:

  1. Creating a new screen widget
  2. Adding navigation from home screen
  3. Implementing your Unity integration
  4. Testing and iterating

Troubleshooting

Unity View Not Displaying

  • Check Unity project is exported correctly
  • Verify platform-specific setup (Android/iOS)
  • Check console for initialization errors

No Communication

  • Ensure onEngineCreated is called
  • Verify Unity script is attached
  • Check message target names match

Performance Issues

  • Enable message batching for high-frequency updates
  • Use throttling for UI controls
  • Profile with DevTools

The example app is a complete reference implementation - use it as a starting point for your own projects!

Next Steps