Forums

OverviewV-Play 2 Support (Qt 5) › Sprite play upon event

Viewing 10 posts - 1 through 10 (of 10 total)
  • Author
    Posts
  • #15123

    Todd

    Hi,

    So now I am trying to figure out how to make a sprite play upon an event.

    How would I make a bomb play my explosive sprite upon player colliding?

     

    #15127

    Marcin

    Hi Todd,
    In general there are few ways to do it.
    But I think the flow is something like this, most of the time:
    In your collider(the one one the player entity or bomb) you create event listener(singal listener in Qt case), and then either trigger another signal or call your custom handler explicitly.

    Later, in your handler, you change your bomb sprites.

    To create signal listener  on collider check http://v-play.net/doc/vplay-boxcollider/, look for onBeginContact, there you can execute some action on contact
    To dynamically change animation for sprite, between “states” I strongly recommend to read this http://v-play.net/doc/vplay-spritesequencevplay/
    In general, use SpriteSequenceVPlay where you switch between animation “states”.
    Check the docs I put, there are very good examples which cover basic and advanced usage.
    There is no point to put any code because it would be almost 1:1 with the examples in the docs, at least in my case.

     

    PS. I strongly recommend to read this http://v-play.net/doc/vplay-qml-communication-basics/, how to communicate between entities and which way to use, and when.

     

    #15229

    Todd

    Hey thanks for the help,

    I’m just now getting to this, been super busy with school.

    So I am going in and trying to set an event handler but I cant quite get it to work…

    Basically in my game I just want to set a sprite to play on collision when the plane hits the bomb.

    This is my current code in the bomb.qml,

    EntityBase {
    id: bomb
    entityType: “Bomb”
    width: 20
    height: 20
    property int bomb: 90
    property int variationDistance: 130
    property double delay: 0
    MultiResolutionImage {
    id: bombs
    width: bomb.width
    height: bomb.height
    source: “../../assets/img/bomb.png”
    }
    BoxCollider {
    id: collider
    width: bomb.width
    height: bomb.height
    anchors.centerIn: bomb
    bodyType: Body.Static
    collisionTestingOnlyMode: true
    fixture.onBeginContact: {
    player.gameOver()
    }
    fixture.onBeginContact: {
    SpriteSequenceVPlay{
    id: explosion
    defaultSource: “explosivesprite.png”
    SpriteVPlay{
    name: “hit”
    frameWidth: 28
    frameHeight: 26
    frameCount: 21
    startFrameColumn: 1
    frameRate: 15
    }
    }
    }
    MovementAnimation {
    id: animation
    target: bomb
    property: “x”
    velocity: -150
    running: true
    minPropertyValue: -80
    onLimitReached: {
    bomb.x = 400
    bomb.y = 30+Math.random()*200
    }
    function generateRandomValueBetween(minimum, maximum) {
    return Math.random()*(maximum-minimum) + minimum
    }
    function reset() {
    bomb.x = scene.gameWindowAnchorItem.width+bomb.width/2
    bomb.y = generateRandomValueBetween(-variationDistance, variationDistance)-scene.height/3
    }
    function start() {
    delayTimer.restart()
    }
    function stop() {
    animation.stop()
    delayTimer.stop()
    }
    Timer {
    id: delayTimer
    interval: delay*1000
    repeat: false
    onTriggered: {
    animation.start()
    }
    }
    Component.onCompleted: {
    reset()
    }
    }
    }
    }

    Again, thanks for the help!

    #15231

    Günther
    V-Play Team

    Hi Todd!

    The fixture.onBeginContact signal allows to define a handler function with code that should be executed when the signal is fired.
    It is not possible to add a visual item within this code by simply declaring the QML item in this function. You can only add QML items in this declarative way within other QML items, but not within functions.

    To dynamically add a visual QML Item in this code, it is necessary to manually create the item and add it as a child to one of your existing visual components.
    Have a look at Dynamic Object Creation in QML if you’re interested in doing this. However, please note that this means that a new item will be created whenever the collision happens, but the item is never removed afterwards, which makes things a bit more complicated as you need to destroy the explosion-sprite again to avoid filling up your memory with more and more explosion-items.

     

    I would recommend to add one explosion sprite directly to the entity, but hide it initially. Whenever the onBeginContact signal fires, you can simply start the animation and do not have to worry about creating and destroying QML items.

    You can do that with something like this:

    BoxCollider {
        id: collider
        width: bomb.width
        height: bomb.height
        anchors.centerIn: bomb
        bodyType: Body.Static
        collisionTestingOnlyMode: true
        fixture.onBeginContact: {
          player.gameOver()
        }
    
        fixture.onBeginContact: {
          // play explosion
          explosion.jumpTo("hit")
          explosion.visible = true
        }
      }
    
      // define explosion sprite as child of the bomb entity
      SpriteSequenceVPlay {
        id: explosion
        defaultSource: "explosivesprite.png"
        anchors.centerIn: parent
    
        // initially hide the explosion sprite
        visible: false
        SpriteVPlay {
          name: "hidden"
          frameWidth: 28
          frameHeight: 26
          frameCount: 1
          to: { "hidden" } // stay hidden if in hidden state
        }
    
        // the actual hit animation
        SpriteVPlay{
          name: "hit"
          frameWidth: 28
          frameHeight: 26
          frameCount: 21
          startFrameColumn: 1
          frameRate: 15
          to: { "hidden" } // go to hidden state after hit animation is finished
        }
    
        // set sprite invisible if it enters state "hidden"
        onCurrentSpriteChanged: {
          if(currentSprite === "hidden")
            explosion.visible = false
        }
      }

     

     

    Best,
    Günther

     

    #15617

    Todd

    Hey again,

     

    yeah so I went in and attempted to do what you say and trying different things but I cant get the sprite to play… the game runs and everything but the sprite is not playing on contact, this is the way I have everything.

     

    import VPlay 2.0
    import QtQuick 2.0

    EntityBase {

    id: bomb
    entityType: “Bomb”
    width: 20
    height: 20

    property int bomb: 90
    property int variationDistance: 130
    property double delay: 0

    MultiResolutionImage {
    id: bombs
    width: bomb.width
    height: bomb.height

    source: “../../assets/img/bomb.png”

    }
    BoxCollider {
    id: collider
    width: bomb.width
    height: bomb.height
    anchors.centerIn: bomb
    bodyType: Body.Static
    collisionTestingOnlyMode: true
    fixture.onBeginContact: {
    player.gameOver()
    }

    BoxCollider {
    id: collider
    width: bomb.width
    height: bomb.height
    anchors.centerIn: bomb
    bodyType: Body.Static
    collisionTestingOnlyMode: true
    fixture.onBeginContact: {
    player.gameOver()
    }

    fixture.onBeginContact: {
    // play explosion
    explosion.jumpTo(“hit”)
    explosion.visible = true
    }
    }

    // define explosion sprite as child of the bomb entity
    SpriteSequenceVPlay {
    id: explosion
    defaultSource: “explosivesprite.png”
    anchors.centerIn: parent

    // initially hide the explosion sprite
    visible: false
    SpriteVPlay {
    name: “hidden”
    frameWidth: 28
    frameHeight: 26
    frameCount: 1
    to: { “hidden” } // stay hidden if in hidden state
    }

    // the actual hit animation
    SpriteVPlay{
    name: “hit”
    frameWidth: 28
    frameHeight: 26
    frameCount: 21
    startFrameColumn: 1
    frameRate: 15
    to: { “hidden” } // go to hidden state after hit animation is finished
    }

    // set sprite invisible if it enters state “hidden”
    onCurrentSpriteChanged: {
    if(currentSprite === “hidden”)
    explosion.visible = false
    }
    }
    MovementAnimation {
    id: animation
    target: bomb
    property: “x”
    velocity: -150
    running: true
    minPropertyValue: -80
    onLimitReached: {
    bomb.x = 400
    bomb.y = 30+Math.random()*200
    }
    function generateRandomValueBetween(minimum, maximum) {
    return Math.random()*(maximum-minimum) + minimum
    }
    function reset() {
    bomb.x = scene.gameWindowAnchorItem.width+bomb.width/2
    bomb.y = generateRandomValueBetween(-variationDistance, variationDistance)-scene.height/3
    }
    function start() {
    delayTimer.restart()
    }
    function stop() {
    animation.stop()
    delayTimer.stop()
    }
    Timer {
    id: delayTimer
    interval: delay*1000
    repeat: false
    onTriggered: {
    animation.start()
    }
    }
    Component.onCompleted: {
    reset()
    }
    }

    }
    }

     

    Thanks for working with me, I am learning a lot 😀

    #15618

    Todd

    Yeah one thing I noticed is that the documentation is saying the dynamic components needs to be called by using the QTcreateComponent() function. Pretty unclear on this, does this function need to be put in under bomb.qml or does it need to be created with a new file?

    #15621

    Alex
    V-Play Team

    Hi Todd,

    the first thing that jumps to my eyes is that you are having 2 colliders that have the same size and both call player.gameOver() upon collision. And the second collider uses the fixture.onBeginContact signal twice, which should already give you a warning in the editor. So please merge both colliders to a single one and use fixture.onBeginContact only once per collider. This might already be the issue.

    Cheers,
    Alex

    PS: when posting code in the forums, please use the “Code” button in the toolbar of the reply-textbox, that makes it more readable :)

    #15622

    Günther
    V-Play Team

    Hi Todd!

    Can you check if the SpriteSequence on its own is set up correctly? (image source, frame width/height/count settings, …)
    I also made a small mistake before by accidentally defining fixture.onBeginContact twice (once for the gameover call and once for starting the sprite sequence). Sorry for that!

    This is how it should look like correctly:

    import VPlay 2.0
    import QtQuick 2.0
    
    EntityBase {
      id: bomb
      entityType: "Bomb"
      width: 20
      height: 20
    
      property int bomb: 90
      property int variationDistance: 130
      property double delay: 0
    
      MultiResolutionImage {
        id: bombs
        width: bomb.width
        height: bomb.height
        source: "../../assets/img/bomb.png"
      }
    
      BoxCollider {
        id: collider
        width: bomb.width
        height: bomb.height
        anchors.centerIn: bomb
        bodyType: Body.Static
        collisionTestingOnlyMode: true
        fixture.onBeginContact: {
          player.gameOver()
    
          // play explosion
          explosion.jumpTo("hit")
          explosion.visible = true
        }
      }
    
      // define explosion sprite as child of the bomb entity
      SpriteSequenceVPlay {
        id: explosion
        defaultSource: "explosivesprite.png"
        anchors.centerIn: parent
    
        // initially hide the explosion sprite
        visible: false
        SpriteVPlay {
          name: "hidden"
          frameWidth: 28
          frameHeight: 26
          frameCount: 1
          to: { "hidden": 1 } // stay hidden if in hidden state
        }
    
        // the actual hit animation
        SpriteVPlay{
          name: "hit"
          frameWidth: 28
          frameHeight: 26
          frameCount: 21
          startFrameColumn: 1
          frameRate: 15
          to: { "hidden": 1 } // go to hidden state after hit animation is finished
        }
    
        // set sprite invisible if it enters state “hidden”
        onCurrentSpriteChanged: {
          if(currentSprite === "hidden")
            explosion.visible = false
        }
      }
    
      MovementAnimation {
        id: animation
        target: bomb
        property: "x"
        velocity: -150
        running: true
        minPropertyValue: -80
        onLimitReached: {
          bomb.x = 400
          bomb.y = 30+Math.random()*200
        }
        function generateRandomValueBetween(minimum, maximum) {
          return Math.random()*(maximum-minimum) + minimum
        }
        function reset() {
          bomb.x = scene.gameWindowAnchorItem.width+bomb.width/2
          bomb.y = generateRandomValueBetween(-variationDistance, variationDistance)-scene.height/3
        }
        function start() {
          delayTimer.restart()
        }
        function stop() {
          animation.stop()
          delayTimer.stop()
        }
        Timer {
          id: delayTimer
          interval: delay*1000
          repeat: false
          onTriggered: {
            animation.start()
          }
        }
        Component.onCompleted: {
          reset()
        }
      }
    }
    

     

    About Qt.createComponent

    It’s not required to focus on this for the beginning, but this is how it works:
    Every QML file you create is a QML Component which usually has a visual representation and comes with signals and properties that allow to customize the component when you use it. For example, if you define a component MyButton.qml you will probably have a text property and a clicked signal. When using this component, you can then set a different text and clicked-behavior for each button that you add in your application:

    MyButton {
      text: "Click Me"
      onClicked: {
        doSomething()
      }
    }

    Now let’s talk about component creation. In your qml folder you currently have one Main.qml file, which holds the GameWindow item. The GameWindow is the root component which holds all other items. When you run the app, the application automatically loads the Main.qml and creates the GameWindow with all it’s children. This means for example that your whole game is created at startup with all components like scenes and entities that you directly added to the QML files in your project.

    The running game then also contains some game logic, e.g. signal handlers for reacting to user input, handlers to react to collisions or code that you run using a Timer. This code actually brings your game alive and links all the components together to create your game.
    For example, you can change properties or call functions of the existing items in your game (like show and start the bomb sprite sequence).
    To add a new component within this code that does not yet exist (like you initially tried with your bomb), it is required to dynamically create and add the component with Qt.createComponent. This is a bit complex and can be avoided by statically adding and reusing items (like my suggested solution for your bomb).

    As you often need to dynamically add game entities like enemies or obstacles, we provide our EntityManager which automatically keeps track of all dynamically created components, allows to retrieve certain items via their id or e.g. remove all created enemies/obstacles when the game ends.

    I hope this helps to shine some light on this topic?

    Best,
    Günther

    #15630

    Todd

    Hey thank you!

    I still havent been able to get the sprite to play, but yes i believe i have the sprite sequence set up right. However I get an error message from the output saying it cannot open the picture i have for the sprite…

     

     

    qrc:///qml/VPlay/sprites/SpriteVPlay.qml:70:3: QML Sprite: Cannot open: file:///C:/Users/todd/Downloads/resources_flappybird_vplay2 (5)/qml/entities/explosivesprite.png

    qrc:///qml/VPlay/sprites/SpriteVPlay.qml:70:3: QML Sprite: Cannot open: file:///C:/Users/todd/Downloads/resources_flappybird_vplay2 (5)/qml/entities/explosivesprite.png

    qrc:///qml/VPlay/sprites/SpriteVPlay.qml:70:3: QML Sprite: Cannot open: file:///C:/Users/todd/Downloads/resources_flappybird_vplay2 (5)/qml/entities/explosivesprite.png

    qrc:///qml/VPlay/sprites/SpriteVPlay.qml:70:3: QML Sprite: Cannot open: file:///C:/Users/todd/Downloads/resources_flappybird_vplay2 (5)/qml/entities/explosivesprite.png

     

    Not sure why this is happening, didnt do it for any of the other assets

    #15632

    Todd

    Update,

    I got the sprite to play! Turned out i needed to add the resource file to the qrc for some reason!

Viewing 10 posts - 1 through 10 (of 10 total)

RSS feed for this thread

You must be logged in to reply to this topic.

Voted #1 for:

  • Easiest to learn
  • Most time saving
  • Best support

Develop Cross-Platform Apps and Games 50% Faster!

  • Voted the best supported, most time-saving and easiest to learn cross-platform development tool
  • Based on the Qt framework, with native performance and appearance on all platforms including iOS and Android
  • Offers a variety of plugins to monetize, analyze and engage users
FREE!
create apps
create games
cross platform
native performance
3rd party services
game network
multiplayer
level editor
easiest to learn
biggest time saving
best support