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

Durdles - 2-Player Action Game

 import QtQuick 2.0
 import Felgo 4.0
 import "../levels"
 import "../common"
 import ".."

 // the opponent targets the nearest player and attacks him when he is within a specific radius
 EntityBase {
   id: opponent
   entityType: "opponent"

   // make the twoAxisController and other variables acessible from outside
   property alias opponent: opponent
   property alias opponentBody: opponentBody
   property alias circleCollider: circleCollider
   property alias shootSound1: shootSound1
   property alias shootSound2: shootSound2

   // the current target
   property bool targetTankRed: true

   // the visual representation of the opponent
   AnimatedImage {
     playing: false
     id: opponentBody
     width: 20
     height: 27
     rotation: 180
     anchors.centerIn: parent
     z: 2
   }

   // the shadow beneath the opponent
   Image {
     id: shadow
     width: 20
     height: 27
     rotation: 180
     anchors.centerIn: parent
     source: Qt.resolvedUrl("../../assets/img/Shadow.png")
     z: 1
   }

   // plays when opponent shoots
   GameSoundEffect {
     volume: 0.3
     id: shootSound1
     // an ogg file is not playable on windows, because the extension is not supported!
     source: Qt.resolvedUrl("../../assets/snd/Snowman1.wav")
   }

   // plays when opponent shoots
   GameSoundEffect {
     volume: 0.3
     id: shootSound2
     source: Qt.resolvedUrl("../../assets/snd/Snowman2.wav")
   }

   // play one of two random shoot sounds
   function shoot() {
     var random = Math.floor(Math.random() * 2) + 1 //Sounds 1 - 2
     if (random == 1){
       shootSound1.play()
     }else{
       shootSound2.play()
     }
   }

   CircleCollider {
     id: circleCollider
     radius: 10
     x: -radius
     y: -radius
     bodyType: Body.Static
   }

   // targets the nearest tank and shots when he is within a certain radius
   MoveToPointHelper {
     enabled: GameInfo.gamePaused ? false : true
     id: moveToPointHelper

     // pick the target object with the help of a boolean
     targetObject: targetTankRed ? tankRed : tankBlue;

     // only shots when the tank is within a specified range
     property bool opponentShooting: false

     // shots within this range
     distanceToTargetThreshold: 80

     // calculates the distance between the opponent and the two players every 100ms
     Timer {
       interval: 100;
       running: GameInfo.gamePaused ? false : true;
       repeat: GameInfo.gamePaused ? false : true;

       onTriggered: {
         // calculate the distance with the pythagoras and target the nearest tank
         var distanceRed = Math.sqrt(Math.pow(tankRed.x - opponent.x, 2) + Math.pow(tankRed.y - opponent.y, 2));
         var distanceBlue = Math.sqrt(Math.pow(tankBlue.x - opponent.x, 2) + Math.pow(tankBlue.y - opponent.y, 2));
         targetTankRed = (distanceRed >= distanceBlue) ? false : true;
       }
     }

     // shot at the player every 3000ms as long as he is within the specific range
     Timer {
       interval: 3000;
       running: GameInfo.gamePaused ? false : true;
       repeat: GameInfo.gamePaused ? false : true;

       onTriggered: {
         if (parent.opponentShooting) {
           // play the animation and sound
           opponentBody.playing=true;
           shoot();

           // calculate specific parameters to create the bullet
           // calculate the distance
           var distanceRed = Math.sqrt(Math.pow(tankRed.x - opponent.x, 2) + Math.pow(tankRed.y - opponent.y, 2));
           var distanceBlue = Math.sqrt(Math.pow(tankBlue.x - opponent.x, 2) + Math.pow(tankBlue.y - opponent.y, 2));

           // calculate the target point of the nearest tank
           var tankX
           var tankY
           if (distanceRed <= distanceBlue){
             tankX = tankRed.x
             tankY = tankRed.y
           }
           else{
             tankX = tankBlue.x
             tankY = tankBlue.y
           }

           // calculate the vector with the angle and speed
           var angle = Math.atan2(tankY-opponent.y, tankX-opponent.x) * 180 / Math.PI
           var speed = 100
           var xDirection = Math.cos(angle * Math.PI / 180.0) * speed
           var yDirection = Math.sin(angle * Math.PI / 180.0) * speed

           // translate from the center of the opponent to a specified direction for the starting point
           var startX = (16 * Math.cos((angle) * Math.PI / 180)) + opponent.x
           var startY = (16 * Math.sin((angle) * Math.PI / 180)) + opponent.y

           // create the bullet entity with the calculated parameters
           entityManager.createEntityFromComponentWithProperties(
                 bulletOpponent, {
                   start: Qt.point(startX, startY),
                   rotation : angle + 90,
                   velocity: Qt.point(xDirection, yDirection)
                 });
         }
       }
     }

     // check the current distance and stop or continue shoting
     onDistanceToTargetChanged: {
       if (distanceToTarget < distanceToTargetThreshold) {
         opponentShooting = true
       } else {
         opponentShooting = false
       }
     }
   }

   // rotate the opponent in the direction of the nearest tank
   MovementAnimation {
     target: opponent
     property: "rotation"
     velocity: 300*moveToPointHelper.outputXAxis

     // start rotating towards the target immediately
     running: true

     // this avoids over-rotating, so rotating further than allowed
     maxPropertyValueDifference: moveToPointHelper.absoluteRotationDifference
   }

   // the bullet of the opponent
   Component {
     id: bulletOpponent

     EntityBase {
       id: singleBulletOpponent
       entityType: "singleBulletOpponent"

       property point start
       property point velocity

       x: start.x
       y: start.y

       // the visual representation of the bullet
       Image {
         width: 7
         height: 14
         source: Qt.resolvedUrl("../../assets/img/Iceball.png")
         anchors.centerIn: parent
       }

       BoxCollider {
         id: boxCollider

         width: 10
         height: 10
         anchors.fill: parent
         collisionTestingOnlyMode: true

         density: 0
         friction: 0
         restitution: 0
         body.bullet: true
         body.fixedRotation: false // if set to true the physics engine will NOT apply rotation to it

         // handle the collision
         fixture.onBeginContact: (other, contactNormal) => {
           var collidedEntity = other.getBody().target;
           var otherEntityId = collidedEntity.entityId;
           var otherEntityParent = collidedEntity.parent;

           // destroy the bullet if it collided with anything but a lake or a powerup and create a splat image
           if (otherEntityId.substring(0, 3) !== "lak" && otherEntityId.substring(0, 3) !== "pow" && otherEntityId.substring(0, 3) !== "opp") {
             singleBulletOpponent.destroy();

             entityManager.createEntityFromUrlWithProperties(
                   Qt.resolvedUrl("Splat.qml"), {
                     "z": 1,
                     "x": singleBulletOpponent.x,
                     "y": singleBulletOpponent.y,
                     "rotation": singleBulletOpponent.rotation
                   }
                   );

             // check if it hit a player
             if (otherEntityId.substring(0, 4) === "tank") {
               // call damage method of playerRed or playerBlue
               otherEntityParent.onDamage();
             }
           }
         }
       }

       // animate the movement of the bullet over the x-axis
       MovementAnimation {
         target: singleBulletOpponent
         property: "x"
         velocity: singleBulletOpponent.velocity.x
         running: true
       }

       // animate the movement of the bullet over the y-axis
       MovementAnimation {
         target: singleBulletOpponent
         property: "y"
         velocity: singleBulletOpponent.velocity.y
         running: true
         onStopped: {
           singleBulletOpponent.destroy()
         }
       }
     }
   }

   // calculate the angle between a zero and point and another one
   function calcAngle(touchX, touchY) {
Qt_Technology_Partner_RGB_475 Qt_Service_Partner_RGB_475_padded