By the end of this lesson, you will be able to:
ℹ️ Info Definition: Mobile game development combines programming, design, and psychology to create engaging interactive experiences. Modern games use frameworks like React Native Game Engine, Unity, and custom JavaScript solutions to deliver smooth, addictive gameplay.
Mobile gaming is the largest entertainment industry:
Category | Examples | Key Features |
---|---|---|
Hyper-Casual | Flappy Bird, 2048 | Simple mechanics, instant play |
Puzzle | Candy Crush, Monument Valley | Problem-solving, progression |
Strategy | Clash of Clans, Chess | Planning, resource management |
Action | PUBG Mobile, Fruit Ninja | Real-time interaction, reflexes |
Educational | Duolingo, Khan Academy Kids | Learning through gameplay |
💡 Success Story: Flappy Bird was built in just 2-3 days and earned $50,000 per day at its peak!
# Game engine for React Native
npm install react-native-game-engine
# Physics engine
npm install matter-js
npm install react-native-matter-js
# Animation libraries
npx expo install react-native-reanimated
npx expo install react-native-gesture-handler
# Sound effects
npx expo install expo-av
# Device sensors
npx expo install expo-sensors
npx expo install expo-accelerometer
npx expo install expo-gyroscope
// types/GameTypes.ts
export interface Position {
x: number;
y: number;
}
export interface GameObject {
id: string;
position: Position;
size: { width: number; height: number };
velocity?: Position;
color?: string;
type: string;
}
export interface GameState {
entities: { [key: string]: GameObject };
score: number;
level: number;
gameStatus: 'playing' | 'paused' | 'gameOver' | 'menu';
time: number;
}
// games/BubblePopGame.tsx
import React, { useState, useEffect, useCallback } from 'react';
import {
View,
TouchableWithoutFeedback,
Dimensions,
StyleSheet,
Text,
Alert,
} from 'react-native';
import { GameEngine } from 'react-native-game-engine';
import Animated, {
useSharedValue,
useAnimatedStyle,
withSpring,
withTiming,
runOnJS,
} from 'react-native-reanimated';
const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window');
interface Bubble {
id: string;
x: number;
y: number;
size: number;
color: string;
speed: number;
popped: boolean;
}
interface GameStats {
score: number;
level: number;
lives: number;
timeLeft: number;
}
const COLORS = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7', '#DDA0DD'];
export const BubblePopGame: React.FC = () => {
const [bubbles, setBubbles] = useState<Bubble[]>([]);
const [gameStats, setGameStats] = useState<GameStats>({
score: 0,
level: 1,
lives: 3,
timeLeft: 60,
});
const [gameState, setGameState] = useState<'menu' | 'playing' | 'paused' | 'gameOver'>('menu');
const [isGameRunning, setIsGameRunning] = useState(false);
// Game loop
useEffect(() => {
let gameInterval: NodeJS.Timeout;
let spawnInterval: NodeJS.Timeout;
let timerInterval: NodeJS.Timeout;
if (isGameRunning && gameState === 'playing') {
// Main game loop - move bubbles
gameInterval = setInterval(() => {
setBubbles(prevBubbles => {
return prevBubbles.map(bubble => ({
...bubble,
y: bubble.y + bubble.speed,
})).filter(bubble => {
// Remove bubbles that went off screen
if (bubble.y > SCREEN_HEIGHT + 50 && !bubble.popped) {
// Lost a life
setGameStats(prev => ({ ...prev, lives: prev.lives - 1 }));
return false;
}
return bubble.y < SCREEN_HEIGHT + 100;
});
});
}, 16); // ~60fps
// Spawn new bubbles
spawnInterval = setInterval(() => {
spawnBubble();
}, 1000 - (gameStats.level * 100)); // Faster spawning as level increases
// Game timer
timerInterval = setInterval(() => {
setGameStats(prev => {
const newTimeLeft = prev.timeLeft - 1;
if (newTimeLeft <= 0) {
setGameState('gameOver');
return prev;
}
return { ...prev, timeLeft: newTimeLeft };
});
}, 1000);
}
return () => {
clearInterval(gameInterval);
clearInterval(spawnInterval);
clearInterval(timerInterval);
};
}, [isGameRunning, gameState, gameStats.level]);
// Check for game over
useEffect(() => {
if (gameStats.lives <= 0) {
setGameState('gameOver');
setIsGameRunning(false);
}
}, [gameStats.lives]);
// Level progression
useEffect(() => {
const newLevel = Math.floor(gameStats.score / 500) + 1;
if (newLevel > gameStats.level) {
setGameStats(prev => ({ ...prev, level: newLevel, timeLeft: prev.timeLeft + 30 }));
Alert.alert('Level Up!', `Welcome to Level ${newLevel}!`);
}
}, [gameStats.score]);
const spawnBubble = useCallback(() => {
const newBubble: Bubble = {
id: Date.now().toString() + Math.random(),
x: Math.random() * (SCREEN_WIDTH - 60),
y: -60,
size: 40 + Math.random() * 40,
color: COLORS[Math.floor(Math.random() * COLORS.length)],
speed: 1 + Math.random() * 2 + gameStats.level * 0.5,
popped: false,
};
setBubbles(prev => [...prev, newBubble]);
}, [gameStats.level]);
const popBubble = useCallback((bubbleId: string) => {
setBubbles(prev => {
return prev.map(bubble => {
if (bubble.id === bubbleId && !bubble.popped) {
// Calculate score based on bubble size and level
const points = Math.floor((100 - bubble.size) * gameStats.level);
setGameStats(prevStats => ({ ...prevStats, score: prevStats.score + points }));
return { ...bubble, popped: true };
}
return bubble;
});
});
// Remove popped bubble after animation
setTimeout(() => {
setBubbles(prev => prev.filter(bubble => bubble.id !== bubbleId));
}, 300);
}, [gameStats.level]);
const startGame = () => {
setBubbles([]);
setGameStats({
score: 0,
level: 1,
lives: 3,
timeLeft: 60,
});
setGameState('playing');
setIsGameRunning(true);
};
const pauseGame = () => {
if (gameState === 'playing') {
setGameState('paused');
setIsGameRunning(false);
} else if (gameState === 'paused') {
setGameState('playing');
setIsGameRunning(true);
}
};
const resetGame = () => {
setIsGameRunning(false);
setGameState('menu');
setBubbles([]);
};
const renderBubble = (bubble: Bubble) => {
return (
<BubbleComponent
key={bubble.id}
bubble={bubble}
onPop={() => popBubble(bubble.id)}
/>
);
};
return (
<View style={styles.container}>
{/* Game HUD */}
<View style={styles.hud}>
<Text style={styles.hudText}>Score: {gameStats.score}</Text>
<Text style={styles.hudText}>Level: {gameStats.level}</Text>
<Text style={styles.hudText}>Lives: {'❤️'.repeat(gameStats.lives)}</Text>
<Text style={styles.hudText}>Time: {gameStats.timeLeft}s</Text>
</View>
{/* Game Area */}
<TouchableWithoutFeedback onPress={pauseGame}>
<View style={styles.gameArea}>
{bubbles.map(renderBubble)}
</View>
</TouchableWithoutFeedback>
{/* Game State Overlays */}
{gameState === 'menu' && (
<View style={styles.overlay}>
<Text style={styles.title}>🫧 Bubble Pop</Text>
<Text style={styles.instruction}>Pop bubbles before they fall!</Text>
<TouchableWithoutFeedback onPress={startGame}>
<View style={styles.button}>
<Text style={styles.buttonText}>Start Game</Text>
</View>
</TouchableWithoutFeedback>
</View>
)}
{gameState === 'paused' && (
<View style={styles.overlay}>
<Text style={styles.title}>Game Paused</Text>
<TouchableWithoutFeedback onPress={pauseGame}>
<View style={styles.button}>
<Text style={styles.buttonText}>Resume</Text>
</View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={resetGame}>
<View style={[styles.button, styles.secondaryButton]}>
<Text style={styles.buttonText}>Main Menu</Text>
</View>
</TouchableWithoutFeedback>
</View>
)}
{gameState === 'gameOver' && (
<View style={styles.overlay}>
<Text style={styles.title}>Game Over!</Text>
<Text style={styles.finalScore}>Final Score: {gameStats.score}</Text>
<Text style={styles.finalScore}>Level Reached: {gameStats.level}</Text>
<TouchableWithoutFeedback onPress={startGame}>
<View style={styles.button}>
<Text style={styles.buttonText}>Play Again</Text>
</View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={resetGame}>
<View style={[styles.button, styles.secondaryButton]}>
<Text style={styles.buttonText}>Main Menu</Text>
</View>
</TouchableWithoutFeedback>
</View>
)}
</View>
);
};
// Bubble Component with Animation
const BubbleComponent: React.FC<{
bubble: Bubble;
onPop: () => void;
}> = ({ bubble, onPop }) => {
const scale = useSharedValue(1);
const opacity = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ scale: scale.value }],
opacity: opacity.value,
}));
const handlePress = useCallback(() => {
if (!bubble.popped) {
// Pop animation
scale.value = withSpring(1.3, undefined, () => {
scale.value = withTiming(0, { duration: 200 });
opacity.value = withTiming(0, { duration: 200 });
});
runOnJS(onPop)();
}
}, [bubble.popped, onPop]);
return (
<TouchableWithoutFeedback onPress={handlePress}>
<Animated.View
style={[
styles.bubble,
{
left: bubble.x,
top: bubble.y,
width: bubble.size,
height: bubble.size,
borderRadius: bubble.size / 2,
backgroundColor: bubble.color,
},
animatedStyle,
]}
/>
</TouchableWithoutFeedback>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#87CEEB',
},
hud: {
flexDirection: 'row',
justifyContent: 'space-around',
paddingTop: 50,
paddingBottom: 10,
backgroundColor: 'rgba(255, 255, 255, 0.9)',
},
hudText: {
fontSize: 16,
fontWeight: 'bold',
color: '#2C3E50',
},
gameArea: {
flex: 1,
position: 'relative',
},
bubble: {
position: 'absolute',
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.3,
shadowRadius: 4,
elevation: 5,
},
overlay: {
...StyleSheet.absoluteFillObject,
backgroundColor: 'rgba(0, 0, 0, 0.8)',
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 32,
fontWeight: 'bold',
color: 'white',
marginBottom: 20,
textAlign: 'center',
},
instruction: {
fontSize: 18,
color: 'white',
marginBottom: 30,
textAlign: 'center',
},
finalScore: {
fontSize: 20,
color: '#FFD700',
marginBottom: 10,
textAlign: 'center',
},
button: {
backgroundColor: '#4ECDC4',
paddingHorizontal: 40,
paddingVertical: 15,
borderRadius: 25,
marginBottom: 15,
},
secondaryButton: {
backgroundColor: '#95A5A6',
},
buttonText: {
color: 'white',
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
export default BubblePopGame;
// engines/PhysicsGameEngine.ts
import { Dimensions } from 'react-native';
import Matter from 'matter-js';
const { width, height } = Dimensions.get('window');
export class PhysicsGameEngine {
private engine: Matter.Engine;
private world: Matter.World;
private bodies: Matter.Body[] = [];
constructor() {
this.engine = Matter.Engine.create();
this.world = this.engine.world;
// Set gravity
this.engine.world.gravity.y = 0.8;
// Create boundaries
this.createBoundaries();
}
private createBoundaries() {
const ground = Matter.Bodies.rectangle(
width / 2,
height - 10,
width,
20,
{ isStatic: true }
);
const leftWall = Matter.Bodies.rectangle(
10,
height / 2,
20,
height,
{ isStatic: true }
);
const rightWall = Matter.Bodies.rectangle(
width - 10,
height / 2,
20,
height,
{ isStatic: true }
);
Matter.World.add(this.world, [ground, leftWall, rightWall]);
}
addCircle(x: number, y: number, radius: number, options?: any) {
const circle = Matter.Bodies.circle(x, y, radius, {
restitution: 0.8,
friction: 0.3,
...options,
});
Matter.World.add(this.world, circle);
this.bodies.push(circle);
return circle;
}
addRectangle(x: number, y: number, width: number, height: number, options?: any) {
const rectangle = Matter.Bodies.rectangle(x, y, width, height, {
restitution: 0.6,
friction: 0.3,
...options,
});
Matter.World.add(this.world, rectangle);
this.bodies.push(rectangle);
return rectangle;
}
applyForce(body: Matter.Body, force: { x: number; y: number }) {
Matter.Body.applyForce(body, body.position, force);
}
removeBody(body: Matter.Body) {
Matter.World.remove(this.world, body);
this.bodies = this.bodies.filter(b => b !== body);
}
update() {
Matter.Engine.update(this.engine, 16); // 60fps
return this.bodies.map(body => ({
id: body.id,
x: body.position.x,
y: body.position.y,
angle: body.angle,
}));
}
detectCollisions() {
const pairs = Matter.Pairs.create();
const collisions: Array<{ bodyA: Matter.Body; bodyB: Matter.Body }> = [];
// Simple collision detection
for (let i = 0; i < this.bodies.length; i++) {
for (let j = i + 1; j < this.bodies.length; j++) {
const bodyA = this.bodies[i];
const bodyB = this.bodies[j];
if (Matter.Bounds.overlaps(bodyA.bounds, bodyB.bounds)) {
collisions.push({ bodyA, bodyB });
}
}
}
return collisions;
}
}
// stores/GameStore.ts
import { create } from 'zustand';
interface Player {
id: string;
name: string;
level: number;
experience: number;
coins: number;
achievements: string[];
inventory: GameItem[];
}
interface GameItem {
id: string;
name: string;
type: 'weapon' | 'powerup' | 'cosmetic';
rarity: 'common' | 'rare' | 'epic' | 'legendary';
owned: boolean;
}
interface GameStore {
// Player state
player: Player;
currentGame: string | null;
highScores: Record<string, number>;
// Game state
gameSettings: {
soundEnabled: boolean;
musicEnabled: boolean;
hapticEnabled: boolean;
difficulty: 'easy' | 'medium' | 'hard';
};
// Actions
updatePlayer: (updates: Partial<Player>) => void;
addExperience: (amount: number) => void;
spendCoins: (amount: number) => boolean;
earnCoins: (amount: number) => void;
updateHighScore: (gameType: string, score: number) => void;
unlockAchievement: (achievementId: string) => void;
purchaseItem: (item: GameItem) => boolean;
}\n\nexport const useGameStore = create<GameStore>((set, get) => ({\n player: {\n id: 'player1',\n name: 'Player',\n level: 1,\n experience: 0,\n coins: 100,\n achievements: [],\n inventory: [],\n },\n currentGame: null,\n highScores: {},\n gameSettings: {\n soundEnabled: true,\n musicEnabled: true,\n hapticEnabled: true,\n difficulty: 'medium',\n },\n\n updatePlayer: (updates) => set((state) => ({\n player: { ...state.player, ...updates }\n })),\n\n addExperience: (amount) => set((state) => {\n const newExp = state.player.experience + amount;\n const newLevel = Math.floor(newExp / 1000) + 1;\n const leveledUp = newLevel > state.player.level;\n \n if (leveledUp) {\n // Level up rewards\n const coinReward = newLevel * 50;\n return {\n player: {\n ...state.player,\n experience: newExp,\n level: newLevel,\n coins: state.player.coins + coinReward,\n }\n };\n }\n \n return {\n player: { ...state.player, experience: newExp }\n };\n }),\n\n spendCoins: (amount) => {\n const { player } = get();\n if (player.coins >= amount) {\n set((state) => ({\n player: { ...state.player, coins: state.player.coins - amount }\n }));\n return true;\n }\n return false;\n },\n\n earnCoins: (amount) => set((state) => ({\n player: { ...state.player, coins: state.player.coins + amount }\n })),\n\n updateHighScore: (gameType, score) => set((state) => ({\n highScores: {\n ...state.highScores,\n [gameType]: Math.max(state.highScores[gameType] || 0, score)\n }\n })),\n\n unlockAchievement: (achievementId) => set((state) => {\n if (!state.player.achievements.includes(achievementId)) {\n return {\n player: {\n ...state.player,\n achievements: [...state.player.achievements, achievementId],\n coins: state.player.coins + 100, // Achievement reward\n }\n };\n }\n return state;\n }),\n\n purchaseItem: (item) => {\n const { spendCoins } = get();\n const cost = getItemCost(item);\n \n if (spendCoins(cost)) {\n set((state) => ({\n player: {\n ...state.player,\n inventory: [...state.player.inventory, { ...item, owned: true }]\n }\n }));\n return true;\n }\n return false;\n },\n}));\n\nconst getItemCost = (item: GameItem): number => {\n const baseCosts = {\n common: 50,\n rare: 200,\n epic: 500,\n legendary: 1000,\n };\n return baseCosts[item.rarity];\n};\n```\n\n## 🤖 AI-Powered Game Features\n\n### AI Game Content Generator\n\n```typescript\n// services/GameAI.ts\nimport OpenAI from 'openai';\n\ninterface GameLevel {\n id: string;\n difficulty: number;\n obstacles: Obstacle[];\n enemies: Enemy[];\n rewards: Reward[];\n timeLimit?: number;\n}\n\ninterface Obstacle {\n type: string;\n position: { x: number; y: number };\n properties: Record<string, any>;\n}\n\nclass GameAI {\n private openai: OpenAI;\n\n constructor(apiKey: string) {\n this.openai = new OpenAI({ apiKey });\n }\n\n async generateLevel(\n gameType: string,\n playerSkill: number,\n previousLevels: GameLevel[]\n ): Promise<GameLevel> {\n const prompt = `\n Generate a game level for a ${gameType} game.\n Player skill level: ${playerSkill}/10\n Previous levels completed: ${previousLevels.length}\n \n Create a balanced level with:\n - Appropriate difficulty progression\n - Varied obstacle placement\n - Engaging enemy patterns\n - Fair reward distribution\n \n Return as JSON with obstacles, enemies, and rewards arrays.\n `;\n\n try {\n const response = await this.openai.chat.completions.create({\n model: 'gpt-4',\n messages: [{ role: 'user', content: prompt }],\n temperature: 0.7,\n });\n\n const levelData = JSON.parse(response.choices[0].message.content || '{}');\n \n return {\n id: `level_${Date.now()}`,\n difficulty: Math.min(playerSkill + 1, 10),\n ...levelData,\n };\n } catch (error) {\n console.error('Level generation error:', error);\n return this.generateFallbackLevel(playerSkill);\n }\n }\n\n async balanceGameplay(\n gameStats: {\n winRate: number;\n averageScore: number;\n sessionLength: number;\n difficultyRating: number;\n }\n ): Promise<{\n adjustments: Record<string, number>;\n recommendations: string[];\n }> {\n const prompt = `\n Analyze these game statistics and suggest balance adjustments:\n - Win rate: ${gameStats.winRate * 100}%\n - Average score: ${gameStats.averageScore}\n - Average session: ${gameStats.sessionLength} minutes\n - Difficulty rating: ${gameStats.difficultyRating}/10\n \n Target: 60-70% win rate, 5-10 minute sessions, 6-7 difficulty\n \n Return JSON with numerical adjustments and text recommendations.\n `;\n\n try {\n const response = await this.openai.chat.completions.create({\n model: 'gpt-3.5-turbo',\n messages: [{ role: 'user', content: prompt }],\n temperature: 0.3,\n });\n\n return JSON.parse(response.choices[0].message.content || '{}');\n } catch (error) {\n console.error('Gameplay balancing error:', error);\n return { adjustments: {}, recommendations: [] };\n }\n }\n\n async generateQuests(\n playerLevel: number,\n completedQuests: string[],\n playerPreferences: string[]\n ): Promise<Array<{\n id: string;\n title: string;\n description: string;\n objectives: string[];\n rewards: string[];\n difficulty: number;\n }>> {\n const prompt = `\n Generate 3 unique quests for a player:\n - Player level: ${playerLevel}\n - Completed quests: ${completedQuests.length}\n - Preferences: ${playerPreferences.join(', ')}\n \n Create engaging, varied quests with clear objectives and appropriate rewards.\n Return as JSON array.\n `;\n\n try {\n const response = await this.openai.chat.completions.create({\n model: 'gpt-4',\n messages: [{ role: 'user', content: prompt }],\n temperature: 0.8,\n });\n\n return JSON.parse(response.choices[0].message.content || '[]');\n } catch (error) {\n console.error('Quest generation error:', error);\n return [];\n }\n }\n\n private generateFallbackLevel(playerSkill: number): GameLevel {\n return {\n id: `fallback_${Date.now()}`,\n difficulty: playerSkill,\n obstacles: [\n {\n type: 'wall',\n position: { x: 200, y: 300 },\n properties: { width: 50, height: 100 },\n },\n ],\n enemies: [\n {\n type: 'basic',\n position: { x: 300, y: 200 },\n properties: { speed: 2, health: 1 },\n },\n ],\n rewards: [\n {\n type: 'coin',\n position: { x: 400, y: 250 },\n properties: { value: 10 },\n },\n ],\n };\n }\n}\n\nexport default GameAI;\n```\n\n## 📊 Game Analytics and Optimization\n\n### Performance Monitoring\n\n```typescript\n// hooks/useGamePerformance.ts\nimport { useState, useEffect, useCallback } from 'react';\n\ninterface PerformanceMetrics {\n fps: number;\n memoryUsage: number;\n batteryUsage: number;\n renderTime: number;\n}\n\nexport const useGamePerformance = () => {\n const [metrics, setMetrics] = useState<PerformanceMetrics>({\n fps: 60,\n memoryUsage: 0,\n batteryUsage: 0,\n renderTime: 0,\n });\n\n const [isOptimized, setIsOptimized] = useState(true);\n\n const measureFrameRate = useCallback(() => {\n let frames = 0;\n let lastTime = Date.now();\n\n const tick = () => {\n frames++;\n const currentTime = Date.now();\n \n if (currentTime - lastTime >= 1000) {\n const fps = Math.round(frames * 1000 / (currentTime - lastTime));\n setMetrics(prev => ({ ...prev, fps }));\n \n // Auto-optimize if performance is poor\n if (fps < 30 && isOptimized) {\n optimizePerformance();\n }\n \n frames = 0;\n lastTime = currentTime;\n }\n \n requestAnimationFrame(tick);\n };\n \n requestAnimationFrame(tick);\n }, [isOptimized]);\n\n const optimizePerformance = useCallback(() => {\n setIsOptimized(false);\n \n // Reduce particle effects\n // Lower animation quality\n // Reduce physics calculations\n // Implement object pooling\n \n console.log('Game performance optimized for better frame rate');\n }, []);\n\n useEffect(() => {\n measureFrameRate();\n }, [measureFrameRate]);\n\n return {\n metrics,\n isOptimized,\n optimizePerformance,\n };\n};\n```\n\n## 📝 Summary\n\nIn this lesson, you learned:\n- How to build interactive mobile games with React Native\n- Implementing physics engines and game mechanics\n- Creating engaging gameplay loops and progression systems\n- Using AI to generate game content and balance difficulty\n- Optimizing game performance for mobile devices\n- Understanding mobile game design patterns and best practices\n\n## 🤖 Practice with AI\n\nCode with AI: Try building these game concepts.\n\n**Prompts to try:**\n- *\"Create a tower defense game with upgradeable towers and wave-based enemies\"*\n- *\"Build a word puzzle game with daily challenges and multiplayer competition\"*\n- *\"Design a racing game with physics-based car controls and track editor\"*\n- *\"Implement a match-3 puzzle game with special power-ups and combo systems\"*\n- *\"Create an endless runner with procedural level generation and character customization\"*\n\nMobile gaming is a massive opportunity - start with simple mechanics and build addictive experiences that players love!