diff --git a/dep/clayground b/dep/clayground index ec9f0ba..2248380 160000 --- a/dep/clayground +++ b/dep/clayground @@ -1 +1 @@ -Subproject commit ec9f0ba15e0847b317f6bc342be7af02fd7f8cad +Subproject commit 2248380bcaf346b69f5db9ed4f7465f8984688b0 diff --git a/src/Enemy.qml b/src/Enemy.qml index 21393cc..5487605 100644 --- a/src/Enemy.qml +++ b/src/Enemy.qml @@ -8,27 +8,75 @@ import Clayground.ScalingCanvas 1.0 GameEntity { id: theEnemy + + source: gameWorld.resource("visual/enemy.png"); bodyType: Body.Dynamic bullet: true sensor: true categories: collCat.enemy - collidesWith: collCat.player + collidesWith: collCat.player | collCat.waypoint | collCat.garden + property var wpPath: [] + property int _wpIndex: -1 + property real maxVelo: 10 + debug: true + text: theMunchTimer.running ? "Munch Time" : "Hunnngry" + signal attack(var damage) Component.onCompleted: { for (let i=0; i 1) { + v = v.times(maxVelo/l); + linearVelocity.x = v.x; + linearVelocity.y = v.y; + } + } + else { + linearVelocity.x = 0; + linearVelocity.y = 0; } } function _onCollision(fixture) { var e = fixture.getBody().target; - if (theWorld.isInstanceOf(e, "Player")) { + if (gameWorld.isInstanceOf(e, "Player")) { if (e.isDodging) theEnemy.destroy(); else e.energy -= 1; } + else if (gameWorld.isInstanceOf(e, "Waypoint")) { + _goForNextWp(); + } + else if (gameWorld.isInstanceOf(e, "Garden")) { + theMunchTimer.start(); + } + } + + function _onEndContact() { + var e = fixture.getBody().target; + if (gameWorld.isInstanceOf(e, "Garden")) { + theMunchTimer.stop(); + } } - property int energy: 10000 + Timer { + id: theMunchTimer + interval: 1000 + onTriggered: attack(2); + repeat: true + } } diff --git a/src/EnemyMaster.qml b/src/EnemyMaster.qml new file mode 100644 index 0000000..8c6557e --- /dev/null +++ b/src/EnemyMaster.qml @@ -0,0 +1,81 @@ +// (c) serein.pfeiffer@gmail.com - zlib license, see "LICENSE" file +import QtQuick 2.12 +import Clayground.Physics 1.0 +import Clayground.ScalingCanvas 1.0 +import QtQuick.Shapes 1.14 +import Box2D 2.0 + +Item { + id: theMaster + property var path: [] + property var _waypoints: [] + property var gameWorld: parent + property var _spawned: [] + onEnabledChanged: { + if (enabled) spawnTimer.start(); + else spawnTimer.stop(); + } + + Component.onCompleted: { + let lenWuH = 1.0; + for (let i=1; i {return gameWorld.pixelPerUnit;} ); + enemy.active = Qt.binding( _ => {return gameWorld.running;} ); + _spawned.push(enemy); + } + } + + Component { id: theSpawner; Enemy {} } + + + ScalingPoly { + canvas: gameWorld + strokeStyle: ShapePath.DashLine + dashPattern: [ 1, 4 ] + vertices: path + strokeColor: "red" + opacity: .5 + } + + Component.onDestruction: { + spawnTimer.stop() + for (let i=0; i<_spawned.length; ++i) { + let ent = _spawned[i]; + if (typeof ent !== 'undefined' && + ent.hasOwnProperty("destroy")) + ent.destroy(); + } + _spawned = []; + } +} diff --git a/src/GameEntity.qml b/src/GameEntity.qml index d692caa..298f949 100644 --- a/src/GameEntity.qml +++ b/src/GameEntity.qml @@ -11,6 +11,7 @@ VisualizedBoxBody property bool debug: false property string text: "" + property var gameWorld: theWorld Loader { sourceComponent: debug ? theDebugTxtComp : null } Component { id: theDebugTxtComp diff --git a/src/Garden.qml b/src/Garden.qml index d03daec..d7e61d4 100644 --- a/src/Garden.qml +++ b/src/Garden.qml @@ -20,7 +20,7 @@ GameEntity // Energy of the garden, if it is 0, the garden dead property int energy: maxEnergy // Protection decreases dealt damage - property int protection: 0 + property real protection: 0 text: energy + "/" + protection @@ -41,6 +41,9 @@ GameEntity protection = fixture.protection; } } + else if (theWorld.isInstanceOf(e, "Enemy")) { + e.attack.connect(_onAttack); + } } function _onEndContact(fixture) { @@ -48,10 +51,13 @@ GameEntity if (theWorld.isInstanceOf(e, "Player")) { if (fixture.hasOwnProperty("protection")) protection = 0; } + else if (theWorld.isInstanceOf(e, "Enemy")) { + e.attack.disconnect(_onAttack); + } } function _onAttack(damage) { - let d = damage > protection ? damage - protection : 0; + let d = damage * ((protection > 0) ? protection : 1) energy -= d; } } diff --git a/src/Player.qml b/src/Player.qml index e572c6e..6d1427d 100644 --- a/src/Player.qml +++ b/src/Player.qml @@ -62,7 +62,7 @@ GameEntity sensor: true categories: collCat.magicProtection collidesWith: collCat.garden - property int protection: thePlayer.isProtecting ? 2 : 0 + property real protection: thePlayer.isProtecting ? .5 : 0 } } diff --git a/src/Sandbox.qml b/src/Sandbox.qml index 391b01f..8318c60 100644 --- a/src/Sandbox.qml +++ b/src/Sandbox.qml @@ -13,6 +13,7 @@ ClayWorld { pixelPerUnit: height/70 gravity: Qt.point(0,0) timeStep: 1/60.0 + running: false property var player: null //physicsDebugging: true @@ -25,12 +26,13 @@ ClayWorld { readonly property int naturalForce: Box.Category4 readonly property int garden: Box.Category5 readonly property int magicProtection: Box.Category6 + readonly property int waypoint: Box.Category7 readonly property int noCollision: Box.None } onWorldAboutToBeCreated: { + running = false; player = null; - theWeather.running = false; } onWorldCreated: { // theGameCtrl.selectKeyboard(Qt.Key_Up, @@ -41,10 +43,10 @@ ClayWorld { // Qt.Key_S); theGameCtrl.selectGamepad(0, true); theWorld.observedItem = player; - theWeather.running = true; + theWorld.running = true; } - Weather {id: theWeather } + Weather {id: theWeather; enabled: theWorld.running } Referee { id: theReferee anchors.horizontalCenter: parent.horizontalCenter @@ -65,14 +67,16 @@ ClayWorld { id: theGameCtrl anchors.fill: parent + property bool inGameCtrlEnabled: theWorld.running && theWorld.player + onButtonAPressedChanged: { - if (!player) return; + if (!inGameCtrlEnabled) return; if (player.isProtecting) return; player.moveSpeed = buttonAPressed ? 35 : 18; } onButtonBPressedChanged: { - if (!player) return; + if (!inGameCtrlEnabled) return; let p = player; if (buttonBPressed) { if (p.desiresToMove) p.dodgeSpeed = 75; @@ -83,14 +87,14 @@ ClayWorld { } onAxisXChanged: { - if (!player) return; + if (!inGameCtrlEnabled) return; if (player.isProtecting) return; if (axisX > 0) player.moveRight(); else if (axisX < 0) player.moveLeft(); else { player.stopLeft(); player.stopRight();} } onAxisYChanged: { - if (!player) return; + if (!inGameCtrlEnabled) return; if (player.isProtecting) return; if (axisY > 0) player.moveUp(); else if (axisY < 0) player.moveDown(); @@ -105,14 +109,22 @@ ClayWorld { player = obj; player.source = theWorld.resource("visual/player.png"); } - else if (isInstanceOf(obj, "Enemy")) { - obj.source = theWorld.resource("visual/enemy.png"); - } else if (isInstanceOf(obj, "Garden")) { theReferee.addGarden(obj); } } + Component {id: theEnemyMasterComp; EnemyMaster {}} + onPolylineLoaded: { + let ent = theEnemyMasterComp.createObject(theWorld, + { + path: points, + enabled: theWorld.running + }); + ent.enabled = Qt.binding( _ => {return theWorld.running;} ); + entities.push(ent); + } + SoundEffect { id: bgMusic //TODO Replace music place-holder and react. play diff --git a/src/Waypoint.qml b/src/Waypoint.qml new file mode 100644 index 0000000..516bb1d --- /dev/null +++ b/src/Waypoint.qml @@ -0,0 +1,17 @@ +// (c) serein.pfeiffer@gmail.com - zlib license, see "LICENSE" file +import QtQuick 2.12 +import Clayground.Physics 1.0 +import Box2D 2.0 + +PhysicsItem { + id: thePhyItem + fixtures: [ + Box { + sensor: true + width: thePhyItem.width + height: thePhyItem.height + categories: collCat.waypoint + collidesWith: collCat.enemy + } + ] +} diff --git a/src/Weather.qml b/src/Weather.qml index f8c95e0..c7dcb74 100644 --- a/src/Weather.qml +++ b/src/Weather.qml @@ -4,19 +4,19 @@ import QtQuick 2.12 Item { id: theWeather - property bool running: false signal _destroyStorms() - onRunningChanged: { - if (running) theTimer.start() + onEnabledChanged: { + if (enabled) + theTimer.start(); else { - theTimer.stop() - _destroyStorms() + theTimer.stop(); + _destroyStorms(); } } Timer { id: theTimer - interval: 2000 + interval: 4000 onTriggered: { let x = Math.random() * theWorld.worldXMax let y = Math.random() * theWorld.worldYMax diff --git a/src/map.svg b/src/map.svg index 2266e7d..5cd5a97 100644 --- a/src/map.svg +++ b/src/map.svg @@ -25,9 +25,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="0.98994949" - inkscape:cx="90.879274" - inkscape:cy="356.10426" + inkscape:zoom="1.979899" + inkscape:cx="333.53656" + inkscape:cy="301.28159" inkscape:document-units="mm" inkscape:current-layer="layer1" showgrid="false" @@ -55,7 +55,7 @@ image/svg+xml - + @@ -74,8 +74,8 @@ id="desc5900">{"component":"Wall.qml"} {"component":"Garden.qml"} - - {"component":"Enemy.qml"} - - - {"component":"Enemy.qml"} - - - {"component":"Enemy.qml"} - - - {"component":"Enemy.qml"} - {"component":"Garden.qml"} + + {"component":"EnemyMaster.qml"} + + + {"component":"EnemyMaster.qml"} + + + {"component":"EnemyMaster.qml"} + diff --git a/src/res.qrc b/src/res.qrc index ee95028..718a122 100644 --- a/src/res.qrc +++ b/src/res.qrc @@ -6,12 +6,14 @@ GameEntity.qml Garden.qml Enemy.qml + EnemyMaster.qml Referee.qml Sandbox.qml StartScreen.qml Storm.qml Weather.qml Wall.qml + Waypoint.qml map.svg