Learn what Felgo offers to help your business succeed. Start your free evaluation today! Felgo for Your Business

SlotMachine

The SlotMachine component allows to easily implement a slot machine with multiple reels and rows. It also provides methods to spin or stop the slot machine and lets you access the visible items in each reel and row. More...

Import Statement: import Felgo 4.0
Inherits:

Item

Properties

Signals

Methods

Detailed Description

The SlotMachine component provides a simple way to create a slot machine for games similar to the popular casino slot games. Just have a look at the games of slotomania, Slotpark or Greentube to see such slot games in action!

We also used the SlotMachine component ourselves to create a pirate-themed example slot game called Flask of Rum. Click here for an overview of the game features. You will also find further links to try the demo game or to see the full source code. In addition, we provide a complete step-by-step tutorial how you can create the game here: How to Make a Slot Game with Felgo.

In contrast to the demo game or the tutorial, the following sections of this documentation focus on different ways of how you can use the component. The examples guide you from creating a very simple slot machine up to implementing more complex scenarios, that even include multiple different columns or random items. In the last section, we already show you the basics for using the component to make a typical slot game. However, for a detailed description about how to create a slot game, we recommend to read the Flask of Rum slot game tutorial.

Using a Model and a Delegate to Set Up a Simple Slot Machine

The component is built upon the concept to separate Models and Views in QtQuick. To specify the items that are displayed on each reel, you can simply state your data as the model and set the appearance of the items using a delegate. The component then automatically uses the correct total width and height depending on the size of the items and reels that you add. By default, it comes with three reels (columns of the slot machine) and three rows.

The following code describes a simple slot machine. We keep the default setting of three reels and rows and only set the model and delegate properties:

 import Felgo
 import QtQuick

 SlotMachine {
   model: 10
   delegate: Text {
     text: index
   }
 }

You may use every type of data model that is supported by QML, such as:

  • an integer value.
  • an array.
  • an object instance.
  • or special model components, like the ListModel.

Furthermore, we also provide the unique SlotMachineModel. This model is made especially for the SlotMachine component and allows you to easily set up a typical slot machine for casino slot games.

In the example above, we used an integer value as the model. This fills each slot machine reel with ten items. After that, we set the delegate property to define their appearance. For an integer model, the index of the item is available within the delegate. We use a Text element to display the index, but you could also compose a more complex item or use a custom QML item at this point. The slot machine automatically bases its total size on the size of the text element and the number of reels and rows.

You can then use methods like spin, stop or getItem to work with the slot machine.

As you see, it is very easy to get a basic slot machine up and running. But it might be interesting to use a more complex model for your slot machine.

The following example shows a slot machine that utilizes an array model:

 import Felgo
 import QtQuick

 SlotMachine {
   // set different reel and row count
   rowCount: 2
   reelCount: 4

   // set width hand height for items
   defaultReelWidth: 40
   defaultItemHeight: 40

   // use array as model
   model: ["red", "green", "blue", "grey"]
   delegate: Rectangle {
     color: modelData
   }
 }

This time, we configure the slot machine to have four reels and only two rows. In contrast to the previous example, we set the defaultReelWidth and defaultItemHeight properties to specify the size of the slot machine items. These values are used if no width or height is set in the delegate element, which is the case with our rectangle. Of course, we could also directly set a width and height for the rectangle. In that case, the slot machine then uses the size of the rectangle as the default width and height, unless a different default value is set additionally.

Note: As the Text element in the previous example automatically has a width and height based on the text and font, the defaultReelWidth and defaultItemHeight properties don't apply. The specific width and height of a delegate item will always overwrite the default values - even though the default values are used to calculate the total width and height of slot machine. This behavior is necessary, as it is possible to use independent delegates with different item sizes for each reel of a slot machine. You also find such examples at a later point in the documentation.

The example above shows the usage of an array model, which is quite similar to the integer model. In addition to the index, we can now also access the modelData variable within the delegate to work with the value of each array item. In our case, we display rectangles on the slot machine reels and color them differently based on the colors in the array.

Creating a Slot Machine with Multiple Individual Reels

When you want to create a slot machine for your game, you might face a scenario where it is required to implement multiple, individual reels. For example, you might want the first reel to contain some colors, but the second reel should use different colors.

Instead of setting a model and a delegate for the whole slot machine, you have the possibility to manually configure each reel with the SlotMachineReel element to achieve this goal:

 import Felgo
 import QtQuick

 SlotMachine {
   defaultReelWidth: 40
   defaultItemHeight: 30

   // configure first reel to show colors
   SlotMachineReel {
     model: ["red", "green", "blue", "grey"]
     delegate: Rectangle {
       color: modelData
     }
   }

   // configure second reel with different colors
   SlotMachineReel {
     model: ["yellow", "cyan", "magenta", "black"]
     delegate: Rectangle {
       color: modelData
     }
   }
 }

This code creates a slot machine with two reels - each with four different colors. It is common that the items of a slot machine have the same size on every reel, as they should form a clean row when aligned next to each other. As we do not set a fixed size in our delegates, we can use the defaultReelWidth and defaultItemHeight properties to easily set the size of the items for both reels.

If no default width and height is set, the component automatically tries to find an item with a fixed size and then uses these values as the default setting. In addition, it is also possible to mix individual reel definitions with automatically generated reels. The following example puts both of these features into action:

 import Felgo
 import QtQuick

 SlotMachine {
   id: slotMachine

   // configure slot machine to use three reels, as only one SlotMachineReel is
   // defined manually the slot machine automatically creates two additional reels
   reelCount: 3

   // set up slot machine to show colored rectangles per default
   model: ["red", "green", "blue", "grey"]
   delegate: Rectangle {
     color: modelData
   }

   // manually configure first reel to only show borders of the rectangle in different colors
   SlotMachineReel {
     model: ["yellow", "cyan", "magenta", "black"]
     delegate: Rectangle {
       width: 40
       height: 25
       border.width: 2
       border.color: modelData
     }
   }
 }

The important part in this example is the setting of the reelCount property in combination with the SlotMachineReel configuration. Every SlotMachineReel element that you add to the slot machine replaces an automatically generated reel. If there are less SlotMachineReel definitions than the desired reelCount, the component tries to generate the remaining reels based on the default model and delegate properties. In our case, we define the first reel with a SlotMachineReel element. It shows the colors yellow, cyan, magenta and black. The component then automatically creates the remaining two reels that contain the colors red, green, blue and grey based on the default values. We also set the delegate of the first reel to only show the borders of the rectangle, whereas the other reels contain filled rectangles.

In this example, we didn't specify a default width and height for the items. The slot machine now tries to find an item with a fixed width and height and uses these values instead. The rectangle of our first reel has a fixed size, which is then also applied to the automatically generated reels. Of course, it would also work the other way round. Pretty nice!

One part that we didn't cover yet is how to create individual reels that don't share any width or height settings. Also, we may skip the model and delegate definition for SlotMachineReel elements and use the default setting of the slot machine instead. The next example takes care of these aspects:

 import Felgo
 import QtQuick

 SlotMachine {
   // configure slot machine to use three reels, the component creates
   // one additional reel, because only two reels are defined manually
   reelCount: 3

   // set default sizes
   defaultReelWidth: 50
   defaultItemHeight: 25

   // set up slot machine to show colored rectangles per default
   model: ["red", "green", "blue", "grey"]
   delegate: Rectangle {
     color: modelData
   }

   // set first reel to show different colors and be wider (but use the default delegate)
   SlotMachineReel {
     width: 75
     model: ["yellow", "cyan", "magenta", "black"]
   }

   // set second reel to only show borders and use a different size
   SlotMachineReel {
     width: 75
     delegate: Rectangle {
       width: 50
       height: 75
       border.width: 2
       border.color: modelData
       anchors.horizontalCenter: parent.horizontalCenter
     }
   }
 }

This example perfectly shows the flexibility of the slot machine component. The default size for each item of the slot machine is set to 50 x 25. As we use three reels and three rows, the slot machine has a total width of 150 and a height of 75. The default model and delegate describe rectangles in red, green, blue and grey. We then use a SlotMachineReel definition to change the colors of the first reel to yellow, cyan, magenta and black. The appearance of the rectangles matches the default delegate, which is why we do not set a different delegate. But we want the reel to be bigger, so we set the width to 75. The default delegate, that describes the colored rectangle, hasn't set any fixed width. As a result, the rectangles of the first reel are enlarged to fill the bigger reel width.

For the second reel, we do not set a model and use the default colors. But we change the delegate to only show the borders of the rectangle. We also set the size of the rectangle to 50 x 75. The height of 75 matches the slot machines height, so each rectangle covers all three slot machine rows. Also, we add a padding to the reel by defining a bigger reel width and centering the smaller rectangles horizontally.

This already shows how easy it is to set up a slot machine with default settings, that you you can then overwrite with very little effort to add exceptions. You can also use methods like getReel, addReel and insertReel to modify your SlotMachineReel definitions at a later point during the game.

How to Make a Slot Machine for Slot Games

The most common use-case for a slot machine are slot games like the ones you can find in casinos. Such slot machines consist of multiple reels with different symbols in a random order. You win a certain factor of the amount you bet whenever a line of the same symbol appears on the slot machine. The slot machine is set up in a way, that ensures that every symbol occurs multiple times on a reel. Symbols that only give small rewards are more frequent than symbols with big win factors.

If you want to make such a slot machine, you need a model that fills your reels with random symbols, which is quite a stressful task. To easily fill up your reels with a randomly ordered set of symbols based on a frequency setting, we provide a special SlotMachineModel:

 import Felgo
 import QtQuick

 SlotMachine {
   // slot machine has five reels and three rows
   reelCount: 5
   rowCount: 3

   // the default item size is 60 x 50
   defaultReelWidth: 60
   defaultItemHeight: 50

   // use random model based on symbol types and frequencies for each reel
   model: SlotMachineModel {
     // syntax: "type": { [frequency: <int>, ][data: <var>] }
     symbols: {
       "red":     { frequency: 3 }, // 3 x red
       "green":   { frequency: 3 }, // 3 x green
       "blue":    { frequency: 2 }, // 2 x blue
       "cyan":    { frequency: 2 }, // 2 x cyan
       "magenta": { frequency: 1 }, // 1 x magenta
       "yellow":  { frequency: 1 } // 1 x yellow
     }
   }

   // define appearance of items
   delegate: Item {
     Rectangle {
       color: modelData.type
       anchors.fill: parent
     }
     Text {
       text: modelData.type
       anchors.centerIn: parent
     }
   }
 }

This slot machine consists of five reels and three rows with a default item size of 60 x 50. Each item is displayed as a rectangle of a certain color, that has the name of the color written in its center.

To fill the reels with items, we only define a single model for all the reels. This SlotMachineModel specifies the available symbols and their frequency on each reel. In our case, each reel is randomly filled with three red blocks, three green blocks, two blue blocks, two cyan blocks, one magenta block and one yellow block.

Within the delegate, you can access the data object of the symbol in the same way as you would access the value of an array model:

  • modelData.type contains the symbol name, that matches the property name of your symbol configuration, e.g. "red", "green", "blue", ...
  • modelData.frequency holds the frequency value of the symbol.
  • modelData.data is a special property that allows passing custom user data to your delegate.

You can use the property for custom user data for every purpose you like. For example, if you want to display the slot machine items as images, you could just pass the filename of the image along with the other symbol data and access it with the modelData.data property:

 import Felgo
 import QtQuick

 SlotMachine {
   id: slotMachine

   // slot machine has four reels and two rows
   reelCount: 4
   rowCount: 2

   // the default item size is 50 x 50
   defaultReelWidth: 50
   defaultItemHeight: 50

   // use random items on each reel, pass image source to delegate as data of symbols
   model: SlotMachineModel {
     // syntax: "type": { [frequency: <int>, ][data: <var>] }
     symbols: {
       "square":    { frequency: 3, data: "square.png" },   // 3 x square
       "circle":    { frequency: 2, data: "circle.png" },   // 2 x circle
       "triangle":  { frequency: 2, data: "triangle.png" }, // 2 x triangle
       "diamond" :  { frequency: 1, data: "diamond.png" }   // 1 x diamond
     }
   }

   // show image for each item based on custom user data in symbol configuration
   delegate: Item {
     Image {
       source: "../assets/"+modelData.data
       anchors.fill: parent
     }
   }
 }

You could also use a more complex object instead of a string at this point, the data property is not modified at all and simply passed to the delegate.

As you can see, you can easily implement your own slot machine with random reels by configuring the SlotMachineModel and defining how you want the items to look like. You should be ready to design your own slot machine by now, and by calling the spin or stop method you can already watch the symbols line up in random positions. But maybe you are struggling to check if there are matching symbols aligned next to each other after you stopped the slot machine.

The next example extends the previous slot machine with a check for matching symbols when it is stopped. We also want to add an animation to the items when they match each other. Let's replace the previous slot machine with the following implementation:

 import Felgo
 import QtQuick

 SlotMachine {
   id: slotMachine
   anchors.centerIn: parent

   // slot machine has four reels and two rows
   reelCount: 4
   rowCount: 2

   // the default item size is 50 x 50
   defaultReelWidth: 75
   defaultItemHeight: 75

   // use random items on each reel, pass image source to delegate as data of symbols
   model: SlotMachineModel {
     // syntax: "type": { [frequency: <int>, ][data: <var>] }
     symbols: {
       "square":    { frequency: 3, data: "square.png" },   // 3 x square
       "circle":    { frequency: 2, data: "circle.png" },   // 2 x circle
       "triangle":  { frequency: 2, data: "triangle.png" }, // 2 x triangle
       "diamond" :  { frequency: 1, data: "diamond.png" }   // 1 x diamond
     }
   }

   // show image for each item based on custom user data in symbol configuration
   delegate: Item {
     // show image
     Image {
       id: image
       source: "../../assets/"+modelData.data
       anchors.centerIn: parent
       anchors.fill: parent

       scale: 0.8
     }

     // configure animation to enlarge the item and shrink it again
     SequentialAnimation {
       id: winAnimation

       // make image bigger
       NumberAnimation {
         target: image
         property: "scale"
         duration: 250
         to: 1.0
       }
       // shrink it again
       NumberAnimation {
         target: image
         property: "scale"
         duration: 250
         to: 0.8
       }
     }

     // add a function that starts the animation
     function startWinAnimation() {
       winAnimation.start()
     }
   }

   // check for matching symbols when a spin ends and start the animations
   onSpinEnded: {
     // check every row of the slot machine
     for(var rowIndex = 0; rowIndex < slotMachine.rowCount; rowIndex++) {

       // for every row -> go over all reels and count length of matching symbols
       var length = 0
       var firstSymbol = null
       for(var reelIndex = 0; reelIndex < slotMachine.reelCount; reelIndex++) {

         // get model data of currently visible item
         var modelData = slotMachine.getItemData(reelIndex, rowIndex)

         // memorize type of first symbol
         if(firstSymbol == null)
           firstSymbol = modelData.type

         // increase length if current symbol type matches first symbol of the row
         if(modelData.type === firstSymbol) {
           length++
         }
         // or stop if a different symbol occurs
         else {
           break
         }
       } // end search for matching symbols on the reels

       // if we found a match -> animate the images of the symbols that won
       if(length >= 2) {
         for(var winIndex = 0; winIndex < length; winIndex++) {
           // get image item of the row
           var image = slotMachine.getItem(winIndex, rowIndex)
           image.startWinAnimation()
         }
       } // end animate items

     } // end check every row
   } // end spin ended handler
 }

We added an animation to the delegate of our items to let them get bigger and back to normal whenever we call the startWinAnimation function.

Note: We start with an initial scale of 0.8 to have some space for making the images bigger. If we would use a scale bigger than 1 during the animation, the images would become larger than the intended item height and width and may move into the area of other aligning items or outside the borders of the slot machine.

Except for the changes in the delegate in terms of the animation, we only added a signal handler that is called whenever a slot machine spin is stopped. The algorithm takes care of the following tasks:

  • We want to check all the rows in the slot machine and then look at all the symbols in that row. The first for-loop handles iterating over all the rows.
  • In order to look at the symbols of every row, the second for-loop is set up to iterate over all the reels.
  • For every row, the we memorize the first symbol, and for every symbol that matches the first symbol, we increase the length counter.
  • When we reach a symbol that differs from the first one, we stop the search for this row.
  • But before we move on to the next row, we start the animations for all matching items we have found, if they form at least a line of two symbols.

To successfully implement this algorithm, it is important that we can access the currently visible items of the slot machine. The two functions that the slot machine component provides for this purpose are:

  • getItemData(reelIndex, rowIndex)

    This function returns the model data of the item at a specific reel and row position. We can use this to work with the type, frequency or data properties of our SlotMachineModel configuration.

  • getItem(reelIndex, rowIndex)

    In contrast to the getItemData-function, this function returns the actual item instance of our delegate that we can see in the slot machine. We can use this function to access our image and trigger the animation.

Of course, your slot machine design and the logic for finding, checking and animating matching symbols might get more complex in your project. But the slot machine component should be a great asset to help you get started with the basic mechanics for your slot game. Also, the tutorial How to Make a Slot Game with Felgo might help you with problems like:

  • Creating a slot machine that automatically fills up the whole game window on every device.
  • Defining and checking multiple winning lines.
  • Adding a special wildcard symbol, that may take the place of every other symbol.

Controlling the Outcome

One highly interesting topic is how to control the result of a slot machine. In some cases, it might be cool to set the outcome beforehand and watch the symbols line up just the way you wanted to. For this purpose, we provide a special method stopAt. With this method, you can set the desired item index for each reel. These items then appear on the first row when the slot machine stops. Look at this example to see how you can use it:

 import Felgo
 import QtQuick

 SlotMachine {
   reelCount: 12
   rowCount: 3

   defaultReelWidth: 30
   defaultItemHeight: 30

   model: ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","-"]
   delegate: Item {
     Text {
       text: modelData
       font.pixelSize: 16
     }
   }

   // stop the slot machine at specific positions
   function vplayRocks() {
     stopAt([20, 25 , 14, 10, 26, 23, 25, 16, 13, 1, 9, 17])
   }
 }

The slot machine consists of three rows and 12 reels, which contain the letters A to Z and a dash. The function vplayRocks then uses the stopAt function of the SlotMachine to specify the outcome for each reel. The first reel will show the letter "U" on the first row, the second reel the letter "Z", ... and so on. If this method is called after we spin the slot machine, we can watch the letters appear one after the other in the way we configured them to.

Property Documentation

defaultItemHeight : int

Specifies the default height for all the items on every slot machine reel. If the delegate definition of a SlotMachineReel element does not set a specific height, the default height is used instead. Also, the total height of the slot machine is automatically based on the rowCount and defaultItemHeight property if no fixed height is set. If no defaultItemHeight is specified, the slot machine tries to use the specific height of a reel item as the default height.


defaultReelWidth : int

Specifies the default width for all the reels of the slot machine. If a SlotMachineReel definition does not set a specific width, the default width is used instead. If no defaultReelWidth is set, the component tries to find a reel that has a fixed width or contains items with a fixed width.


delegate : Component

The default delegate that defines the appearance of the reel items. Unless another delegate is set within a specific SlotMachineReel definition, the default delegate is used.


model : var

The default model that is used for all reels, if no other model is specified by a SlotMachineReel definition. To create reels with randomly shuffled items, you can use the special SlotMachineModel.


reelCount : int

Allows to set the number of slot machine reels. If not enough reels are defined by particular SlotMachineReel definitions, the remaining reels are automatically created based on the model, delegate and defaultReelWidth properties of the slot machine.


reelStopDelay : int

When a spinning slot machine is stopped, each reel is stopped after the previous one using a fixed delay. This property defines the delay time in milliseconds. The default delay is 250 milliseconds.


reelsAnchors : alias

Allows changing the anchoring of the reels. If the slot machine is set up with a fixed width and height, you can use this property to position the reels within the slot machine component. By default, the reels are horizontally and vertically centered.


reelsX : alias

Allows setting the x-position of the reels. If the slot machine is created with a fixed width, you can use this property to set the horizontal reel position within the slot machine component. By default, the reels are horizontally centered.


reelsY : alias

Allows setting the y-position of the reels. If the slot machine is created with a fixed height, you can use this property to set the vertical reel position within the slot machine component. By default, the reels are vertically centered.


rowCount : int

Allows to set the number of visible rows that the slot machine shows. By default, a slot machine has three rows.


spinVelocity : int

Defines the movement speed of the reels when they are spinning. The amount describes the velocity in pixels per second. By default, it is set to 500.


[read-only] spinning : alias

Indicates whether the slot machine reels are currently spinning.


[read-only] stopping : alias

Indicates whether the slot machine is in the process of stopping the reels.


Signal Documentation

reelStopped(int index)

After the stop method is called, the machine stops all of it's reel and emits the reelStopped signal for each reel that successfully stopped moving.

Note: The corresponding handler is onReelStopped.


spinEnded()

After the stop method is called, the machine stops all of it's reel and emits the spinEnded signal after the last reel has fully stopped moving.

Note: The corresponding handler is onSpinEnded.


spinStarted()

This signal is emitted when a slot machine spin is started.

Note: The corresponding handler is onSpinStarted.


Method Documentation

addReel(reel)

Appends a new reel to the slot machine after the current last reel. If you want to add a reel without setting any specific reel properties, simply increase the reelCount to generate a reel based on the model, delegate and defaultReelWidth properties of the SlotMachine.


getItem(reelIndex, rowIndex)

Returns the item instance of a specific reel and row of the slot machine.


getItemData(reelIndex, rowIndex)

Returns the model data of an item on a specific reel and row of the slot machine. If the SlotMachineModel is used, each item contains a type, frequency and data property based on your model configuration.


getItemIndex(reelIndex, rowIndex)

Returns the item index of a specific reel and row of the slot machine.


getModel(reelIndex)

Returns the complete model for a specific reel of the slot machine. This can be either the specific model of a SlotMachineReel or the default model of the SlotMachine. If the SlotMachineModel was used, the actual symbol array created by the SlotMachineModel is returned.


getReel(reelIndex)

Returns the SlotMachineReel object for a specific reel in the slot machine. You can then use the object to to access the model, delegate and width settings of the reel.


insertReel(index, reel)

Adds a new reel to the slot machine at a specific position.


setFirstItemIndex(reelIndex, itemIndex)

Sets the index for the first item of a slot machine reel. If multiple rows are defined in the slot machine, the topmost item on the first row is considered the first item of the reel.


spin(stopInterval)

Spins the reels of the slot machine if it is not currently spinning or in the process of stopping. When a spin is successfully started, the spinStarted signal is emitted. Also, the stopInterval parameter may be used to automatically stop the slot machine after the given time in milliseconds has passed.


stop()

If the slot machine is currently spinning, the reels are stopped one after another based on the reelStopDelay property. When the last reel has stopped, the spinEnded signal is emitted.


stopAt(stopPositions)

If the slot machine is spinning, the reels are stopped at a given item index for each reel. The function expects the stopPositions parameter to be an array that holds a target index for each slot machine reel.


updateModel(reelIndex)

Updates the model for a specific reel. The items on the reel are redrawn based on the current model setting. For a SlotMachineModel, new items are generated based on the symbol configuration.


updateModels()

Updates the models of all reels. The items on the reels are redrawn if the model has changed. For a SlotMachineModel, new items are generated based on the symbol configuration.


Qt_Technology_Partner_RGB_475 Qt_Service_Partner_RGB_475_padded