<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Pixi.JS Game</title>
  
  <!-- LOAD PIXI.JS & COLLISION DETECTION & jQuery SUPPORT -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.6/pixi.min.js"></script>
	<script src="https://cdn.rawgit.com/kittykatattack/bump/2fe38b76/bin/bump.js"></script>
	<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
	
	<!-- LOAD ANY CUSTOM CSS RULES THAT MIGHT BE IN THE style.css FILE -->
	<link rel="stylesheet" type="text/css" href="style.css">
  
</head>
<body>
  
  <div id="stage">
    This will contain the PIXI.js stage, you shouldn't see this message when
    running the code a.k.a. Plunker Live Preview
  </div>
  
  <!-- LINK THE JavaScript FILE, DON'T WRITE ANY JavaSript HERE!! -->
  <script type="text/javascript" src="script.js"></script>
</body>
</html>
// Raz: PIXI code goes here
// Raz: I'd recommend using semicolons just like you would in C#
// Raz: I'd also recommend you open up the Chrome Developer tools to check for JavaScript & PIXI errors

// use the WebGL Browser rendering technology by default as it's faster than HTML5 Canvas
var type = "WebGL";

// if it's not supported, then
if (!PIXI.utils.isWebGLSupported()) {
  // use the HTML5 Canvas Browser rendering technology
  type = "canvas";
}

// test PIXI, should output a test message in the Console
PIXI.utils.sayHello(type);

// Aliases to be used from this point forward, simplifies the code
// use http://pixijs.download/release/docs/index.html for more info on each of these
var
  Container = PIXI.Container,
  autoDetectRenderer = PIXI.autoDetectRenderer,
  loader = PIXI.loader,
  resources = PIXI.loader.resources,
  Sprite = PIXI.Sprite,
  Graphics = PIXI.Graphics,
  Texture = PIXI.Texture,
  Text = PIXI.Text,
  collisionDetection = new Bump() // collision detection
;

// Create a Pixi stage and renderer
var
  stage,
  containerElement = $("#stage"), // jQuery object, grab a handle on the <div id="stage"></div> from index.html
  containerWidth, containerHeight, // actual container height/width, determined later
  stageWidth, stageHeight, // stage height/width, determined later
  renderer = autoDetectRenderer(0, 0) // PIXI graphical renderer, don't care about size here
;

// attach the drawing board to the View
containerElement.html(renderer.view);

// get the actual height and width of the HTML container from index.html
containerWidth = containerElement.innerWidth();
containerHeight = containerElement.innerHeight();

// set the stage height and width
stageWidth = containerWidth;
stageHeight = containerHeight;

// create a JSON object container to use when checking stage wall collisions
var stageContainer = {
  x: 0, // top left corner X position
  y: 0, // top left corner Y position
  height: stageHeight,
  width: stageWidth
};

// allow renderer to resize itself as needed
renderer.autoResize = true;

// make sure the drawing board has the size we want, width first, then height
renderer.resize(stageWidth, stageHeight);

// if window dimensions change, resize the stage accordingly
$(window).on('resize', function () {
  containerWidth = containerElement.innerWidth();
  containerHeight = containerElement.innerHeight();
  stageWidth = containerWidth;
  stageHeight = containerHeight;
  renderer.resize(stageWidth, stageHeight);
});

// build a PIXI.js stage
stage = new Container();

var Ball, ball, ball2, CubeDraw, Cube;

/**
 * isNumeric function in Javascript
 * https://gist.github.com/pinalbhatt/9672790
*/
function IsNumeric(n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

Ball = function(options) {

  // current instance
  var $this = this;
  // Pixi.JS object
  var obj;

  // base Pixi.JS object config
  var
    config,
    // default config values if any of them are missing from the options
    baseConfig = {
      dimensions: {
        height: 100, // pixels
        width: 100 // pixels
      },
      position: { // starting position
        x: stageHeight / 2,
        y: stageWidth / 2
      },
      speed: {
        x: 5, // how many pixels at a time will this move on the x axis
        y: 5 // how many pixels at a time will this move on the y axis
      },
      fill: {
        colour: "#66ccff" // hex colour value
      },
      border: {
        colour: "#ff3300", // hex colour value
        width: 4 // pixels
      }
    };

  // constructor
  var Init = function() {

    // if the options object isn't there i.e. not given, then set it to a blank object
    if (!options) options = {};

    // allow the baseConfig values to be overridden by the options values, if any
    config = Object.assign({}, baseConfig, options);
    
    // check speed option
    if (IsNumeric(config.speed)) {
      config.speed = {
        x: config.speed,
        y: config.speed
      };
    }

    // build it
    Build();
    // add it to the stage
    AddToStage();

  };

  // build the object
  var Build = function() {

    var graphic = new Graphics();
    graphic.lineStyle(config.border.width, config.border.colour, 1);
    graphic.beginFill(config.fill.colour);
    graphic.drawRect(0, 0, config.dimensions.height, config.dimensions.width);
    graphic.endFill();

    obj = new Sprite(graphic.generateCanvasTexture());
    obj.x = config.position.x;
    obj.y = config.position.y;
    obj.vx = config.speed.x;
    obj.vy = config.speed.y;

  };

  // add object to stage
  var AddToStage = function() {
    stage.addChild(obj);
  };

  $this.MoveX = function() {
    obj.x += obj.vx;
  };

  $this.MoveY = function() {
    obj.y += obj.vy;
  };
  
  $this.MoveTo = function (x, y) {
    obj.x = x;
    obj.y = y;
  };

  $this.InvertXDirection = function() {
    obj.vx *= -1;
  };

  $this.InvertYDirection = function() {
    obj.vy *= -1;
  };

  $this.IsOffStageXLeft = function() {
    return (obj.x <= 0);
  };
  
  $this.IsOffStageXRight = function() {
    return (obj.x + obj.width) >= stageWidth;
  };

  $this.IsOffStageYTop = function() {
    return (obj.y <= 0);
  };
  
  $this.IsOffStageYBottom = function() {
    return (obj.y + obj.height) >= stageHeight;
  };

  $this.Animate = function() {

    if ($this.IsOffStageXLeft()) {
      $this.MoveTo(0, obj.y); // reposition object so that it's on screen
      $this.InvertXDirection();
    }
    
    if ($this.IsOffStageXRight()) {
      $this.MoveTo(stageWidth - obj.width, obj.y); // reposition object so that it's on screen
      $this.InvertXDirection();
    }

    if ($this.IsOffStageYTop()) {
      $this.MoveTo(obj.x, 0); // reposition object so that it's on screen
      $this.InvertYDirection();
    }
    
    if ($this.IsOffStageYBottom()) {
      $this.MoveTo(obj.x, stageHeight - obj.height); // reposition object so that it's on screen
      $this.InvertYDirection();
    }

    $this.MoveX();
    $this.MoveY();

  };

  // call the constructor
  Init();

};

// a test function to set up a stage with text and render it
function runAnimationTest() {

  // Loop this function at a default rate of 60 frames per second
  requestAnimationFrame(runAnimationTest);

  // perform animation

  // render the stage a.k.a. construct the stage graphically
  renderer.render(stage);

}

Cube = function(options) {

  // current instance
  var $this = this;
  // Pixi.JS object
  var cube;

  // base Pixi.JS object config
  var
    cubeConfig,
    // default config values if any of them are missing from the options
    baseConfig = {
      dimensions: {
        height: 100, // pixels
        width: 100 // pixels
      },
      position: { // starting position
        x: stageHeight / 2,
        y: stageWidth / 2
      },
      speed: {
        x: 5, // how many pixels at a time will this move on the x axis
        y: 5 // how many pixels at a time will this move on the y axis
      },
      fill: {
        colour: "#66ccff" // hex colour value
      },
      border: {
        colour: "#ff3300", // hex colour value
        width: 4 // pixels
      }
    };

  // constructor
  var Init = function() {

    // if the options object isn't there i.e. not given, then set it to a blank object
    if (!options) options = {};

    // allow the baseConfig values to be overridden by the options values, if any
    cubeConfig = Object.assign({}, baseConfig, options);
    
    // check speed option
    if (IsNumeric(cubeConfig.speed)) {
      cubeConfig.speed = {
        x: cubeConfig.speed,
        y: cubeConfig.speed
      };
    }

    // build it
    Cube();
    // add it to the stage
    AddToStage();

  };

  // build the object
  var Cube = function() {

    var graphic = new Graphics();
    graphic.lineStyle(cubeConfig.border.width, cubeConfig.border.colour, 1);
    graphic.beginFill(cubeConfig.fill.colour);
    graphic.drawCircle(0, 0, 30);
    graphic.endFill();

    cube = new Sprite(graphic.generateCanvasTexture());
    cube.x = cubeConfig.position.x;
    cube.y = cubeConfig.position.y;
    cube.vx = cubeConfig.speed.x;
    cube.vy = cubeConfig.speed.y;

  };

  // add object to stage
  var AddToStage = function() {
    stage.addChild(cube);
  };

  $this.MoveX = function() {
    cube.x += cube.vx;
  };

  $this.MoveY = function() {
    cube.y += cube.vy;
  };
  
  $this.MoveTo = function (x, y) {
    cube.x = x;
    cube.y = y;
  };

  $this.InvertXDirection = function() {
    cube.vx *= -1;
  };

  $this.InvertYDirection = function() {
    cube.vy *= -1;
  };

  $this.IsOffStageXLeft = function() {
    return (cube.x <= 0);
  };
  
  $this.IsOffStageXRight = function() {
    return (cube.x + cube.width) >= stageWidth;
  };

  $this.IsOffStageYTop = function() {
    return (cube.y <= 0);
  };
  
  $this.IsOffStageYBottom = function() {
    return (cube.y + cube.height) >= stageHeight;
  };

  $this.Animate = function() {

    if ($this.IsOffStageXLeft()) {
      $this.MoveTo(0, cube.y); // reposition object so that it's on screen
      $this.InvertXDirection();
    }
    
    if ($this.IsOffStageXRight()) {
      $this.MoveTo(stageWidth - cube.width, cube.y); // reposition object so that it's on screen
      $this.InvertXDirection();
    }

    if ($this.IsOffStageYTop()) {
      $this.MoveTo(cube.x, 0); // reposition object so that it's on screen
      $this.InvertYDirection();
    }
    
    if ($this.IsOffStageYBottom()) {
      $this.MoveTo(cube.x, stageHeight - cube.height); // reposition object so that it's on screen
      $this.InvertYDirection();
    }

    $this.MoveX();
    $this.MoveY();

  };

  // call the constructor
  Init();

};

// a test function to set up a stage with text and render it
function runAnimationTest() {

  // Loop this function at a default rate of 60 frames per second
  requestAnimationFrame(runAnimationTest);

  // perform animation
  cubeDraw.Animate();
  ball.Animate();
  ball2.Animate();
  ball3.Animate();

  // render the stage a.k.a. construct the stage graphically
  renderer.render(stage);

}

// build a new ball
ball = new Ball({
  dimensions: {
    height: 100, // pixels
    width: 100 // pixels
  },
  position: { // starting position
    x: stageHeight / 2,
    y: stageWidth / 2
  },
  speed: 5, // value can also be given as { x: X_SPEED, y: Y_SPEED }
  fill: {
    colour: 0xff3300 // hex colour value
  },
  border: {
    colour: 0x66ccff, // hex colour value
    width: 4 // pixels
  }
});

// build a new ball
ball2 = new Ball({
  dimensions: {
    height: 30, // pixels
    width: 50 // pixels
  },
  position: { // starting position
    x: stageHeight / 3,
    y: stageWidth / 2
  },
  speed: 5, // value can also be given as { x: X_SPEED, y: Y_SPEED }
  fill: {
    colour: 0x66ccff // hex colour value
  },
  border: {
    colour: 0xff3300, // hex colour value
    width: 4 // pixels
  }
});

// build a new ball
ball3 = new Ball({
  dimensions: {
    height: 35, // pixels
    width: 30 // pixels
  },
  position: { // starting position
    x: stageHeight / 2,
    y: stageWidth /2
  },
  speed: 5, // value can also be given as { x: X_SPEED, y: Y_SPEED }
  fill: {
    colour: 0xff3300 // hex colour value
  },
  border: {
    colour: 0x66ccff, // hex colour value
    width: 4 // pixels
  }
});

cubeDraw = new Cube({
  dimensions: {
    height: 30, // pixels
    width: 30 // pixels
  },
  position: { // starting position
    x: stageHeight / 2,
    y: stageWidth /2
  },
  speed: 5, // value can also be given as { x: X_SPEED, y: Y_SPEED }
  fill: {
    colour: 0xff3300 // hex colour value
  },
  border: {
    colour: 0x66ccff, // hex colour value
    width: 4 // pixels
  }
});

// call the animation test function (defined above)
runAnimationTest();
/* Styles go here */

* {
  padding: 0;
  margin: 0;
}

#stage {
  position: absolute;
  display: block;
  height: 100%;
  width: 100%;
}