GameInterface Complete Example

Comprehensive demo showing all GameInterface features: buttons, sliders, and number inputs.

game-interfacebuttonsinputsslidersinteractive

Demo

GameInterface creates its own complete UI structure.

Source Code
/**
 * @demo GameInterface Complete Example
 * @description Comprehensive demo showing all GameInterface features: buttons, sliders, and number inputs.
 * @tags game-interface, buttons, inputs, sliders, interactive
 */

import {  GameInterface  } from "../dist/simple-canvas-library.es.js";

// Create a new GameInterface that appends to demo container for proper layout
const demoContainer = document.getElementById('demo-container');
const gi = new GameInterface({
  canvasSize: { width: 400, height: 300 },
  autoresize: true,
  parent: demoContainer || document.body // Fallback to body if container doesn't exist
});

// Game state variables
let ballX = gi.getSize().width / 2;
let ballY = gi.getSize().height / 2;
let ballVelX = 2;
let ballVelY = 2;
let ballSpeed = 2;
let ballSize = 20;
let ballColor = '#007cba';

// Add a top bar with functional buttons
const topBar = gi.addTopBar();

// About button to demonstrate dialog functionality
topBar.addButton({
  text: "About",
  onclick: () => {
    gi.dialog("About This Demo", "This demonstrates the GameInterface.dialog() popup functionality!");
  }
});

// Start button
const startButton = topBar.addButton({
  text: "Start Game",
  style: {
    textColor: 'white',
    color: '#993a3a',
  },
  onclick: () => {
    if (gi.getGameState() === 'stopped') {
      // Reset ball position when starting
      ballX = gi.getSize().width / 2;
      ballY = gi.getSize().height / 2;
      ballVelX = ballSpeed;
      ballVelY = ballSpeed;
      gi.run();
      startButton.setText("Running");
      pauseButton.setText("Pause");
      pauseButton.enable();
    }
  }
});

// Pause/Resume button
const pauseButton = topBar.addButton({
  text: "Pause",
  onclick: () => {
    if (gi.getGameState() === 'running') {
      gi.pause();
      pauseButton.setText("Resume");
      startButton.setText("Paused");
    } else if (gi.getGameState() === 'paused') {
      gi.resume();
      pauseButton.setText("Pause");
      startButton.setText("Running");
    }
  }
});

// Reset button
topBar.addButton({
  text: "Reset",
  onclick: () => {
    gi.reset();
    ballX = gi.getSize().width / 2;
    ballY = gi.getSize().height / 2;
    ballVelX = ballSpeed;
    ballVelY = ballSpeed;
    startButton.setText("Start Game");
    pauseButton.setText("Pause");
    pauseButton.disable();
  }
});

// Initially disable pause button
pauseButton.disable();

// Add a bottom bar with both sliders and number inputs
const bottomBar = gi.addBottomBar();

// Ball speed control using a slider
const speedSlider = bottomBar.addSlider({
  label: "Speed",
  min: 0.5,
  max: 8,
  value: ballSpeed,
  step: 0.5,
  oninput: (value) => {
    ballSpeed = value;
    // Update velocity direction while preserving direction
    ballVelX = ballVelX > 0 ? ballSpeed : -ballSpeed;
    ballVelY = ballVelY > 0 ? ballSpeed : -ballSpeed;
  }
});

// Ball size control using a number input
const sizeInput = bottomBar.addNumberInput({
  label: "Size",
  min: 5,
  max: 50,
  value: ballSize,
  step: 5,
  oninput: (value) => {
    ballSize = value;
  }
});

// Color controls using buttons
const redButton = bottomBar.addButton({
  text: "Red",
  onclick: () => {
    ballColor = '#ff6b6b';
  }
});

const blueButton = bottomBar.addButton({
  text: "Blue",
  onclick: () => {
    ballColor = '#007cba';
  }
});

const greenButton = bottomBar.addButton({
  text: "Green",
  onclick: () => {
    ballColor = '#4ecdc4';
  }
});

// Toggle controls demonstration
const controlsToggle = bottomBar.addButton({
  text: "Hide Controls",
  onclick: function () {
    if (speedSlider.getIsVisible()) {
      speedSlider.hide();
      sizeInput.hide();
      controlsToggle.setText("Show Controls");
    } else {
      speedSlider.show();
      sizeInput.show();
      controlsToggle.setText("Hide Controls");
    }
  }
});

// Game drawing logic - bouncing ball
gi.addDrawing(({ ctx, width, height, stepTime }) => {
  // Only update if game is running
  if (gi.getGameState() !== 'running') {
    // Just redraw the ball in current position if paused
    ctx.clearRect(0, 0, width, height);

    // Draw ball
    ctx.beginPath();
    ctx.arc(ballX, ballY, ballSize / 2, 0, Math.PI * 2);
    ctx.fillStyle = ballColor;
    ctx.fill();
    ctx.strokeStyle = ballColor === '#007cba' ? '#005a8a' : '#333';
    ctx.lineWidth = 2;
    ctx.stroke();

    // Draw "PAUSED" text if paused
    if (gi.getGameState() === 'paused') {
      ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
      ctx.font = '24px Arial';
      ctx.textAlign = 'center';
      ctx.fillText('PAUSED', width / 2, height / 2 - 30);
    }
    return;
  }

  // Clear canvas
  ctx.clearRect(0, 0, width, height);

  // Update ball position based on actual speed
  ballX += ballVelX * (stepTime / 16); // Normalize for 60fps
  ballY += ballVelY * (stepTime / 16);

  // Bounce off walls
  if (ballX <= ballSize / 2 || ballX >= width - ballSize / 2) {
    ballVelX = -ballVelX;
    ballX = Math.max(ballSize / 2, Math.min(width - ballSize / 2, ballX));
  }
  if (ballY <= ballSize / 2 || ballY >= height - ballSize / 2) {
    ballVelY = -ballVelY;
    ballY = Math.max(ballSize / 2, Math.min(height - ballSize / 2, ballY));
  }

  // Draw ball
  ctx.beginPath();
  ctx.arc(ballX, ballY, ballSize / 2, 0, Math.PI * 2);
  ctx.fillStyle = ballColor;
  ctx.fill();
  ctx.strokeStyle = ballColor === '#007cba' ? '#005a8a' : '#333';
  ctx.lineWidth = 2;
  ctx.stroke();
});

// Add click handler to show coordinates
gi.addClickHandler(({ x, y }) => {
  gi.dialog("Click Detected!", `You clicked at position (${Math.round(x)}, ${Math.round(y)})`);
});

// Don't auto-start the game - wait for user to click Start
console.log("GameInterface demo loaded. Click 'Start Game' to begin!");