Jump to content
This forum will be closing down. Please move to the respective dedicated project forums.

Creating a Carousel for displaying and selecting options.


Grim2105
 Share

Recommended Posts

I am trying to create a carousel type effect in Phaser for selecting a character, there are many tutorials on creating a standard Carousel (Website Slideshows etc) but I am trying to create a Carousel that can display up 3 options at once, (if there are 3 to display), which I am not sure if there's a name for this specific type of carousel as my google searches so far haven't turned up anything I can learn from.

Example Image 1

Example Image 2

I cannot work out the logic needed to shift each image into the next slot along when the next and previous functions are called.

this.scrollingOptionsMenu.ShowSelectedOption();

ShowSelectedOption(); is called in the update function of the theme select state, other than this and the Prev(), Next() functions are called on keyboard press left or right respectively other than this all code is in the below file.

I have included the code I have so far below ScrollingOptionsMenu() is called in my create function of the theme select state, the options parameter is an array of files (for now just the thumbnail of each theme) pulled from a json file.

With my own current attempt, the images don't see to move into their new slots and I get an "property of x undefined' which I understand and could limit it going over but I am not really sure if I'm going the 'right' way with this.

Any help appreciated,

Thanks!


function ScrollingOptionsMenu(game, x, y, options)
{
  this.x = x;
  this.y = y;
  this.options = options;
  this.optionsCount = options.length;
  this.game = game;
  this.currentIndex = 0;

  this.leftImage = game.add.sprite(x , y, 'theme1_thumbail');
  this.centerImage = game.add.sprite(x, y, 'theme2_thumbail');
  this.rightImage = game.add.sprite(x , y, 'theme3_thumbail');

  this.ImageGroup = [this.leftImage, this.centerImage, this.rightImage];

  this.leftImage.anchor.setTo(0.5);
  this.centerImage.anchor.setTo(0.5);
  this.rightImage.anchor.setTo(0.5);

  this.leftImage.x = x - this.leftImage.width;
  this.rightImage.x = x + this.rightImage.width;

  this.leftImage.scale.setTo(0.5);
  this.rightImage.scale.setTo(0.5);
  //console.log(width);
  console.log(this.leftImage);
  console.log(this.centerImage);
  console.log(this.rightImage);
}

//Display currently centerImage Option
ScrollingOptionsMenu.prototype.ShowSelectedOption = function()
{
  if(this.currentIndex == 0)
  {
    //if we are at 0 then the left slot should be empty
    this.leftImage.loadTexture('transParent', 0);
    this.centerImage.loadTexture(this.options[this.currentIndex].thumbnail.name, 0);
    this.rightImage.loadTexture(this.options[this.currentIndex+1].thumbnail.name, 0);
  }
  else{
    //if currentIndex is above 0 then place
    this.leftImage.loadTexture(this.options[this.currentIndex-1].thumbnail.name, 0);
    this.centerImage.loadTexture(this.options[this.currentIndex].thumbnail.name, 0);
    this.rightImage.loadTexture(this.options[this.currentIndex+1].thumbnail.name, 0);
  }
}

ScrollingOptionsMenu.prototype.NextOption = function()
{
  this.ChangeIndex(1);
}

ScrollingOptionsMenu.prototype.PreviousOption = function()
{
  this.ChangeIndex(-1);
}

//returns the index of the currently centerImage option
ScrollingOptionsMenu.prototype.GetCurrentIndex = function()
{
  return this.currentIndex;
}


ScrollingOptionsMenu.prototype.ChangeIndex = function(index)
{
  var optionsLength = this.options.length-1;
  if(this.currentIndex + index < 0)
  {
    this.currentIndex = 0;
  }
  else if(this.currentIndex + index > optionsLength)
  {
    this.currentIndex = optionsLength;
  }else{
    this.currentIndex += index;
  }
}

 

Link to comment
Share on other sites

 

My first try at this would be create Option class that extends the Phaser.Sprite, and it would have   prev(), next() methods that handle positioning the object. create a new object/sprite from Option for each of the options.  a static counter will tell each object the initial position each should take.   

Have a group object receives the user events 'prior', 'next' and calls each of the option sprites in turn.

Lately, I got a bit lazy by foregoing class extensions and now use object factory instead, but same idea.

 

 

Link to comment
Share on other sites

 

Below is a sample using text sprites and allows several options.  All that's left is to modify shift() to tween the movement between the old and new positions and scale.  You can also modify posX(), posY(), posScale() to create a full circle carousel.

Live demo on codepen:

 

var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-carousel-demo', { preload: preload, create: create, update: update });


function preload() {

}

function create() {
  var sprite;
  var style = { font: "65px Arial", fill: "#ffffff", align: "center" };
  var textArr=['Apple', 'Bannana', 'Cherry', 'Mango', 'Orange'];
  
  var spriteArr=[];
  var mid = (textArr.length/2)|0;
  console.log('mid: ' + mid);  
  
  var midX = (game.canvas.width/2)|0;
  var midY = (game.canvas.height/2);
  
  var spaceX = (game.canvas.width/textArr.length);
  var spaceY = midY/textArr.length;

    function posX(idx) {
      console.log('posX: idx: ' + idx);
      var x =  (spaceX/2) + 300+ (mid - idx) * spaceX;
      console.log('posX: ' + x);
      return x;
    };  
    function posY(idx) {
      var y = (midY/2) - (Math.abs(mid - idx) * spaceY);
      return y;
    };
    function posScale(idx) {
      var baseY = midY/2;
      var s =  (baseY - (Math.abs(mid - idx) * spaceY)) / baseY;
      return s;      
    };

    function shift() {
      console.log('shfit:');
      console.log('arrlen: ' + spriteArr.length);
      for (var i = 0; i < spriteArr.length; i += 1) {
        var x = posX(i);
        var y = posY(i);
        var sprite = spriteArr[i];
        console.log('shift: i: ' + i + ' sprite: ' + sprite);
        sprite.position.setTo(x,y); 
        var s = posScale(i);
        console.log('s: ' + s);
        sprite.scale.setTo(s);

      }

    };
    function shiftRight() {
      console.log('shiftRight:');
      var o = spriteArr.shift();
      spriteArr.push(o);
      shift();  
    }
    function shiftLeft() {
      console.log('shiftLeft:');
      var o = spriteArr.pop();
      spriteArr.unshift(o);
      shift();  
    }
  
   
  
  for (var i = 0; i < textArr.length; i += 1) {

    sprite = game.add.text(0, 0, textArr[i], style);
    sprite.anchor.setTo(0.5,0);
    spriteArr.push(sprite);
  }
  shift();
  
    var left = game.input.keyboard.addKey(Phaser.Keyboard.LEFT);
    left.onDown.add(shiftLeft, this);

    var right = game.input.keyboard.addKey(Phaser.Keyboard.RIGHT);
    right.onDown.add(shiftRight, this);  
  
};
function update() {
};

 

Link to comment
Share on other sites

The logic looks oke to me. Are you instatiating new objects? I can't find where you are reading property x in the code. Maybe a demo might help.

You can use Phaser.Math.clamp to clamp the index value in changeIndex(). Clamp the index between 0 and imageGroup.length for example to avoid out of range index.

An applied example:

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...