Merge pull request 'move all prepared code from the crawl game' (#1) from first_impl into main

Reviewed-on: #1
This commit is contained in:
Andrei Yankovich 2025-03-13 10:59:12 +00:00
commit 352a81983b
201 changed files with 12532 additions and 183 deletions

9
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "CMake"] [submodule "submodules/QuasarAppLib"]
path = submodules/CMake path = submodules/QuasarAppLib
url = https://github.com/QuasarApp/CMake.git url = https://github.com/QuasarApp/QuasarAppLib.git
[submodule "submodules/CMake"]
path = submodules/CMake
url = https://github.com/QuasarApp/CMake.git

View File

@ -5,8 +5,8 @@
# of this license document, but changing it is not allowed. # of this license document, but changing it is not allowed.
# #
cmake_minimum_required(VERSION 3.18) cmake_minimum_required(VERSION 3.19)
project(ButterflyEngine LANGUAGES CXX) project(Butterfly LANGUAGES CXX)
if(TARGET ${PROJECT_NAME}) if(TARGET ${PROJECT_NAME})
message("The ${PROJECT_NAME} arledy included in main Project") message("The ${PROJECT_NAME} arledy included in main Project")
return() return()
@ -17,46 +17,40 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
if (ANDROID OR IOS) if (ANDROID OR IOS)
set(BUILD_SHARED_LIBS ON) set(BUILD_SHARED_LIBS ON)
endif() endif()
if (NOT QT_VERSION_MAJOR) find_package(Qt6 COMPONENTS Core REQUIRED)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Test QUIET) find_package(Qt6 COMPONENTS Test QUIET)
endif()
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Test QUIET)
include(submodules/CMake/QuasarApp.cmake) include(submodules/QuasarAppLib/CMake/QuasarApp.cmake)
updateGitVars() updateGitVars()
set(ButterflyEngine_VERSION "0.${GIT_COMMIT_COUNT}.${GIT_COMMIT_HASH}") set(BUTTERFLY_ENGINE_VERSION "0.${GIT_COMMIT_COUNT}.${GIT_COMMIT_HASH}")
set(ButterflyEngine_PACKAGE_ID "quasarapp.core.ButterflyEngine")
option(ButterflyEngine_TESTS "This option disables or enables tests of the ${PROJECT_NAME} project" ON) option(BUTTERFLY_ENGINE_TESTS "This option disables or enables tests of the ${PROJECT_NAME} project" ON)
option(ButterflyEngine_EXAMPLE "This option disables or enables example app of the ${PROJECT_NAME} project" ON) option(BUTTERFLY_ENGINE_EXAMPLE "This option disables or enables example app of the ${PROJECT_NAME} project" ON)
if (ANDROID OR IOS OR NOT QT_VERSION_MAJOR OR QA_WASM32) if (ANDROID OR IOS OR QA_WASM32)
set(ButterflyEngine_TESTS OFF CACHE BOOL "This option force disbled for ANDROID IOS QA_WASM32 and Not Qt projects" FORCE) set(BUTTERFLY_ENGINE_TESTS OFF CACHE BOOL "This option force disbled for ANDROID IOS QA_WASM32 and Not Qt projects" FORCE)
endif()
if (NOT QT_VERSION_MAJOR)
set(ButterflyEngine_EXAMPLE OFF CACHE BOOL "This option force disbled for Not Qt projects" FORCE)
endif() endif()
make_directory(Distro) make_directory(Distro)
initAll() initAll()
add_subdirectory(src/Library) add_subdirectory(submodules/QuasarAppLib)
add_subdirectory(src/engine)
if (DEFINED ButterflyEngine_EXAMPLE) if (DEFINED BUTTERFLY_ENGINE_EXAMPLE)
add_subdirectory(src/Example) add_subdirectory(src/example)
endif() endif()
if (ButterflyEngine_TESTS) if (BUTTERFLY_ENGINE_TESTS)
add_subdirectory(tests) add_subdirectory(tests)
else() else()
message("The ${PROJECT_NAME} tests is disabled.") message("The ${PROJECT_NAME} tests is disabled.")

View File

@ -37,7 +37,7 @@ PROJECT_NAME = ButterflyEngine
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = @ButterflyEngine_VERSION@ PROJECT_NUMBER = @BUTTERFLY_ENGINE_VERSION@
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a

35
init.sh
View File

@ -1,35 +0,0 @@
#!/bin/sh
echo "Project name: $1"
if [ $# -ne 1 ]
then
echo "You call this script wtth wrong arguments."
echo "Example for start script:"
echo "./init.sh MyCmakeProject"
exit 1
fi
REPLACESTRING="s+ButterflyEngine+$1+g"
echo $REPLACESTRING
find . -not -path '*/\.*' -type f -exec sed -i $REPLACESTRING {} +
find . -not -path '*/\.*' -type f -exec sed -i $REPLACESTRING {} +
find src -type d -name '*ButterflyEngine*' -exec sh -c 'x="{}"; NEWSTR=$(echo "$x" | sed "s/ButterflyEngine/'$1'/"); mv "$x" "$NEWSTR"' \;
find src -type f -name '*ButterflyEngine*' -exec sh -c 'x="{}"; NEWSTR=$(echo "$x" | sed "s/ButterflyEngine/'$1'/"); mv "$x" "$NEWSTR"' \;
find Deploy -type f -name '*ButterflyEngine*' -exec sh -c 'x="{}"; NEWSTR=$(echo "$x" | sed "s/ButterflyEngine/'$1'/"); mv "$x" "$NEWSTR"' \;
set -e
git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
while read path_key path
do
url_key=$(echo $path_key | sed 's/\.path/.url/')
url=$(git config -f .gitmodules --get "$url_key")
git submodule add $url $path
done

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
</TS>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
</TS>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
</TS>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
</TS>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
</TS>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
</TS>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
</TS>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
</TS>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
</TS>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
</TS>

View File

@ -1,9 +0,0 @@
<RCC>
<qresource prefix="/">
<file>src/ButterflyEngineModule/qmldir</file>
<file>src/ButterflyEngineModule/ButterflyEngine.qml</file>
</qresource>
<qresource prefix="/ButterflyEngineTr">
<file>languages/en.qm</file>
</qresource>
</RCC>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
</TS>

View File

@ -1,3 +0,0 @@
module ButterflyEngineModule
ButterflyEngine 1.0 ButterflyEngine.qml

View File

@ -0,0 +1,30 @@
<RCC>
<qresource prefix="/">
<file>src/ButterflyEngineModule/qmldir</file>
<file>src/ButterflyEngineModule/Crawl.qml</file>
<file>src/ButterflyEngineModule/GraphicItem.qml</file>
<file>src/ButterflyEngineModule/MainMenu.qml</file>
<file>src/ButterflyEngineModule/MainMenuButton.qml</file>
<file>src/ButterflyEngineModule/Metrix.qml</file>
<file>src/ButterflyEngineModule/PagePopUp.qml</file>
<file>src/ButterflyEngineModule/Scene.qml</file>
<file>src/ButterflyEngineModule/SettingsView.qml</file>
<file>src/ButterflyEngineModule/SnakeItem.qml</file>
<file>src/ButterflyEngineModule/DefaultMenu.qml</file>
<file>src/ButterflyEngineModule/AbstractMenuView.qml</file>
<file>src/ButterflyEngineModule/Light.qml</file>
<file>src/ButterflyEngineModule/DayLight.qml</file>
<file>src/ButterflyEngineModule/particles/ParticleEffect.qml</file>
<file>src/ButterflyEngineModule/particles/CrawlVectorDirection.qml</file>
<file>src/ButterflyEngineModule/particles/CrawlTargetDirection.qml</file>
<file>src/ButterflyEngineModule/particles/FireParticel.qml</file>
<file>src/ButterflyEngineModule/particles/Fire.qml</file>
<file>src/ButterflyEngineModule/particles/Wint.qml</file>
<file>src/ButterflyEngineModule/PreviewControl.qml</file>
<file>src/ButterflyEngineModule/StoreView.qml</file>
<file>src/ButterflyEngineModule/SelectLevelView.qml</file>
</qresource>
<qresource prefix="/ButterflyEngineTr">
<file>languages/en.qm</file>
</qresource>
</RCC>

View File

@ -7,33 +7,24 @@
cmake_minimum_required(VERSION 3.18) cmake_minimum_required(VERSION 3.18)
get_filename_component(CURRENT_PROJECT_DIR ${CMAKE_CURRENT_SOURCE_DIR} NAME) set(CURRENT_PROJECT "${PROJECT_NAME}Engine")
add_definitions(-DBUTTERFLY_ENGINE_LIBRARY)
set(CURRENT_PROJECT "${PROJECT_NAME}${CURRENT_PROJECT_DIR}")
add_definitions(-DButterflyEngine_LIBRARY)
file(GLOB_RECURSE SOURCE_CPP file(GLOB_RECURSE SOURCE_CPP
"src/*.cpp" "src/*.cpp"
"src/*.h" "src/*.h"
"*.qrc"
) )
if (${QT_VERSION_MAJOR})
file(GLOB_RECURSE SOURCE_QRC
"*.qrc"
)
endif()
set(PUBLIC_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/public") set(PUBLIC_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/public")
set(PRIVATE_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/private") set(PRIVATE_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/private")
add_library(${CURRENT_PROJECT} ${SOURCE_CPP} ${SOURCE_QRC}) add_library(${CURRENT_PROJECT} ${SOURCE_CPP} )
find_package(Qt6 COMPONENTS Quick Concurrent REQUIRED)
target_link_libraries(${CURRENT_PROJECT} PUBLIC Qt6::Core Qt6::Quick Qt6::Concurrent QuasarApp)
if (${QT_VERSION_MAJOR})
target_link_libraries(${CURRENT_PROJECT} PUBLIC Qt${QT_VERSION_MAJOR}::Core )
endif()
target_include_directories(${CURRENT_PROJECT} PUBLIC ${PUBLIC_INCUDE_DIR}) target_include_directories(${CURRENT_PROJECT} PUBLIC ${PUBLIC_INCUDE_DIR})
target_include_directories(${CURRENT_PROJECT} PRIVATE ${PRIVATE_INCUDE_DIR}) target_include_directories(${CURRENT_PROJECT} PRIVATE ${PRIVATE_INCUDE_DIR})

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>Crawl</name>
<message>
<source>Crawl</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Please Select level. If level is not availabel please bue it first.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DefaultMenu</name>
<message>
<source>Back to menu.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainMenu</name>
<message>
<source>Select level</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Store</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>My Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Exit</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>PreviewControl</name>
<message>
<source>Start</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SelectLevelView</name>
<message>
<source>Select</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsView</name>
<message>
<source>Use Them</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Light</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dark</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>In order for the new theme to take effect, you need to reload the game.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>StoreView</name>
<message>
<source>Buy</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -0,0 +1,8 @@
import QtQuick
import QtQuick.Layouts
GridLayout {
property var model: null
anchors.fill: parent
}

View File

@ -5,7 +5,7 @@
//# of this license document, but changing it is not allowed. //# of this license document, but changing it is not allowed.
//# //#
import QtQuick 2.15 import QtQuick
Item { Item {

View File

@ -0,0 +1,130 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
//import QtQuick.Window
import QtQuick.Controls
import NotifyModule
ApplicationWindow {
id: mainWindow;
visible: true;
width: 1024;
height: 720;
title: qsTr("Crawl");
property var model: engine
Metrix {id: metrix}
Label {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 25
wrapMode: Text.WordWrap
text: qsTr("Please Select level. If level is not availabel please bue it first.")
}
Scene {
id: scane;
worldModel: (model)? model.world : null;
anchors.fill: parent;
}
Scene {
id: nest;
worldModel: (model)? model.nest : null;
anchors.fill: parent;
}
ToolButton {
text: "👾"
font.pixelSize: 35
onClicked: {
mainMenuPopUp.open()
}
visible: !mainMenuPopUp.visible
}
Drawer {
id: mainMenuPopUp
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
height: parent.height
width: parent.width / 3
MainMenu {
id: mainMenu
model: (mainWindow.model)? mainWindow.model.menu: null;
anchors.fill: parent;
}
}
PagePopUp {
id: settingsPopUp
source: SettingsView {
id: settingsView
model: mainMenu.model ? mainMenu.model.userSettingsModel: null
}
standardButtons: Dialog.Save | Dialog.Cancel | Dialog.RestoreDefaults
modal: false;
width: parent.width * 0.8
height: parent.height * 0.8;
onAccepted: {
settingsView.save();
}
onReset: {
settingsView.reset();
}
onOpened: {
settingsView.update();
}
}
PagePopUp {
id: storePopUp
source: StoreView {
id: view
model: mainMenu.model ? mainMenu.model.storeView: null
}
modal: false;
width: parent.width * 0.8
height: parent.height * 0.8;
}
PagePopUp {
id: selectLvl
source: SelectLevelView {
id: selectLvlView
model: mainMenu.model ? mainMenu.model.selectLevelModle: null
}
modal: false;
width: parent.width * 0.8
height: parent.height * 0.8;
}
NotificationServiceView {
anchors.fill: parent;
}
}

View File

@ -0,0 +1,42 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick3D
Node {
id: graphicItem
property var model: null
property int guiId: (model) ? model.guiId : -1;
PointLight {
id : sun
brightness: (model)? model.lightForce * model.visible: 100
color: (model)? model.color: "#ffffff"
castsShadow: (model)? model.castsShadow: 0
shadowFactor: (model)? model.shadowFactor: 0
shadowFilter: (model)? model.shadowFilter: 0
shadowMapFar: (model)? model.shadowMapFar: 0
shadowBias: (model)? model.shadowBias: 0
shadowMapQuality: Light.ShadowMapQualityHigh
Behavior on brightness {
NumberAnimation {
duration: 5000
}
}
}
rotation: (model)? model.rotation: Qt.quaternion(0, 0, 0, 0)
scale: (model)? model.size: Qt.vector3d(0, 0, 0);
position: (model) ? model.position: Qt.vector3d(0,0,0);
visible: sun.brightness
}

View File

@ -0,0 +1,40 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick.Controls.Material
import QtQuick.Controls
import QtQuick.Layouts
AbstractMenuView {
columns: 2
rows: 2
Button {
text: qsTr("Back to menu.")
onClicked: {
if (model) {
model.backToMenu()
}
}
}
MouseArea {
cursorShape: Qt.DragMoveCursor
Layout.fillHeight: true
Layout.fillWidth: true
Layout.columnSpan: 2
Layout.rowSpan: 2
onClicked: {
model.userTap()
}
}
}

View File

@ -0,0 +1,78 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick3D
Model {
id: graphicItem
property var model: null
property int guiId: (model) ? model.guiId : -1;
property bool fMapColor: model && (model.baseColorMap.length ||
model.emissiveMap.length ||
model.roughnessMap.length ||
model.normalMap.length)
property int tilies: 1
DefaultMaterial {
id: defaultMaterial
diffuseColor: (model)? model.color: "#ff1111"
}
PrincipledMaterial {
id: objMaterial
roughness : 1
baseColorMap: Texture {
source: (model)? model.baseColorMap: ""
tilingModeHorizontal: (tilies > 1)? Texture.Repeat : Texture.ClampToEdge
tilingModeVertical: (tilies > 1)? Texture.Repeat : Texture.ClampToEdge
scaleU: tilies
scaleV: tilies
}
emissiveMap: Texture {
source: (model)? model.emissiveMap: ""
tilingModeHorizontal: (tilies > 1)? Texture.Repeat : Texture.ClampToEdge
tilingModeVertical: (tilies > 1)? Texture.Repeat : Texture.ClampToEdge
scaleU: tilies
scaleV: tilies
}
roughnessMap: Texture {
source: (model)? model.roughnessMap: ""
tilingModeHorizontal: (tilies > 1)? Texture.Repeat : Texture.ClampToEdge
tilingModeVertical: (tilies > 1)? Texture.Repeat : Texture.ClampToEdge
scaleU: tilies
scaleV: tilies
}
normalMap: Texture {
source: (model)? model.normalMap: ""
tilingModeHorizontal: (tilies > 1)? Texture.Repeat : Texture.ClampToEdge
tilingModeVertical: (tilies > 1)? Texture.Repeat : Texture.ClampToEdge
scaleU: tilies
scaleV: tilies
}
}
materials: [
(fMapColor)? objMaterial: defaultMaterial
]
rotation: (model)? model.rotation: Qt.quaternion(0, 0, 0, 0)
scale: (model)? model.size: Qt.vector3d(0, 0, 0);
source: (model)? model.mash: "#Cube";
position: (model) ? model.position: Qt.vector3d(0,0,0);
visible: (model)? model.visible: false
}

View File

@ -0,0 +1,33 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick3D
Node {
id: graphicItem
property var model: null
property int guiId: (model) ? model.guiId : -1;
DirectionalLight {
position: Qt.vector3d(0, 0, 0);
brightness: (model)? model.lightForce: 100
color: (model)? model.color: "#ffffff"
castsShadow: (model)? model.castsShadow: 0
shadowFactor: (model)? model.shadowFactor: 0
shadowFilter: (model)? model.shadowFilter: 0
shadowMapFar: (model)? model.shadowMapFar: 0
shadowBias: (model)? model.shadowBias: 0
}
rotation: (model)? model.rotation: Qt.quaternion(0, 0, 0, 0)
scale: (model)? model.size: Qt.vector3d(0, 0, 0);
position: (model) ? model.position: Qt.vector3d(0,0,0);
}

View File

@ -0,0 +1,83 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick.Controls.Material
import QtQuick.Controls
import QtQuick.Layouts
Item {
id: root
property var model: null
visible: Boolean(model && model.visible)
z: 1
GridLayout {
id: columnLayout
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 0
anchors.rightMargin: 0
anchors.bottomMargin: 0
anchors.topMargin: 0
columns: 1
rows: 10
transformOrigin: Item.Center
MainMenuButton {
id: play
text: qsTr("Select level")
onClicked: {
selectLvl.open()
}
}
MainMenuButton {
id: store
text: qsTr("Store")
onClicked: {
storePopUp.open()
}
}
MainMenuButton {
id: settings
text: qsTr("My Settings")
onClicked: {
settingsPopUp.open();
}
}
MainMenuButton {
id: exit
text: qsTr("Exit")
onClicked: {
Qt.quit();
}
}
}
}
/*##^## Designer {
D{i:0;autoSize:true;height:480;width:640}
}
##^##*/

View File

@ -0,0 +1,24 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick.Controls.Material
import QtQuick.Controls
import QtQuick.Layouts
Button {
id: exit
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
font.pixelSize: height * 0.2
display: AbstractButton.TextBesideIcon
spacing: 4
focusPolicy: Qt.StrongFocus
Layout.preferredHeight: parent.height / (parent.rows + 1)
Layout.preferredWidth: parent.width / (parent.columns + 0.5)
}

View File

@ -0,0 +1,34 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick.Window
import QtQuick.Controls.Material
import QtQuick.Controls
Item {
readonly property int pointCount: 100;
readonly property real mm: Screen.pixelDensity
readonly property real sm: 10 * mm
readonly property real dsm: Math.sqrt(Math.pow(Screen.desktopAvailableWidth, 2) + Math.pow(Screen.desktopAvailableHeight, 2)) / sm
readonly property real pt: getfactor(dsm) * sm
readonly property real controlPtMaterial: Material.buttonHeight
readonly property real gamePt: (width < height) ? width / pointCount : height / pointCount;
function getfactor(dsm) {
if (dsm < 30) {
return 0.5
} else if ( dsm < 70) {
return 1
} else if (dsm < 140) {
return 2;
} else
return 4;
}
anchors.fill: parent;
}

View File

@ -0,0 +1,32 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Dialog {
id: pagePopUp
property var source: null
Item {
id: sourceVal
anchors.fill: parent
}
onSourceChanged: {
if (!source)
return;
source.parent = sourceVal;
source.anchors.fill = sourceVal;
}
x: parent.width / 2 - width / 2
y: parent.height / 2 - height / 2
}

View File

@ -0,0 +1,72 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick.Controls.Material
import QtQuick.Controls
import QtQuick.Layouts
AbstractMenuView {
columns: 4
rows: 2
MouseArea {
cursorShape: Qt.DragMoveCursor
Layout.fillHeight: true
Layout.fillWidth: true
Layout.columnSpan: 4
Layout.rowSpan: 1
property bool track: false
property real oldX: 0
property real oldY: 0
onPressed: (mouse) => {
track = true
oldX = mouse.x
oldY = mouse.y
}
onReleased: {
track = false
}
onPositionChanged: (mouse) => {
if (!model) {
return;
}
if (!track) {
return;
}
let delta = mouse.y - oldY;
let radianDeltaY = (delta / (parent.height / 2)) * 45
delta = mouse.x - oldX;
let radianDeltaX = (delta / (parent.width / 2)) * 45
model.mousePositionChanged(radianDeltaX, radianDeltaY)
oldY = mouse.y;
oldX = mouse.x;
}
}
Button {
text: qsTr("Start")
onClicked: {
if (model) {
model.start()
}
}
}
}

View File

@ -0,0 +1,145 @@
import QtQuick
import QtQuick3D
import QtQuick.Controls.Material
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick3D.Particles3D
View3D {
id: scene;
property var worldModel: null;
renderMode: View3D.Offscreen
visible: worldModel && worldModel.visible
Label {
text: scane.renderStats.fps
x: 200
}
PerspectiveCamera {
id: camera
position: (privateRoot.player && privateRoot.releativeCameraPosition)?
Qt.vector3d(privateRoot.player.position.x + privateRoot.releativeCameraPosition.x,
privateRoot.player.position.y + privateRoot.releativeCameraPosition.y,
privateRoot.player.position.z + privateRoot.releativeCameraPosition.z)
:
Qt.vector3d(0,0,100)
rotation: (privateRoot.world)? privateRoot.world.cameraRotation: Qt.quaternion(0,0,0,0)
}
SceneEnvironment {
id: defautlBackground
backgroundMode: SceneEnvironment.Color
clearColor: "#777777"
}
environment: /*(privateRoot.world)? background:*/ defautlBackground
ParticleSystem3D {
id: privateRoot
property var arrayObjects: []
property var gameMenuModel: (worldModel)? worldModel.menu: null
property var player: (worldModel)? worldModel.player: null
property var releativeCameraPosition: (worldModel)? worldModel.cameraReleativePosition: null
property var gameMenu: null
function add (cppObjId) {
if (!worldModel) {
console.log("create object fail")
return;
}
const objModel = worldModel.getItem(cppObjId);
if (!objModel) {
console.log("model of the crawl object is not found");
return;
}
var viewTemplate = objModel.viewTemplate;
var temp = Qt.createComponent(viewTemplate)
if (temp.status === Component.Ready) {
var obj = temp.createObject(privateRoot)
obj.model = objModel;
arrayObjects.push(obj)
} else {
console.log("wrong viewTemplate in model " + temp.errorString());
}
}
function remove(id) {
if (typeof id !== "number" || id < 0) {
console.log("id not found");
return;
}
for (var i = 0; i < arrayObjects.length; ++i) {
if (id === arrayObjects[i].guiId) {
arrayObjects[i].destroy();
arrayObjects.splice(i,1);
}
}
}
Connections {
target: worldModel;
function onSigOBjctsListChanged(diff) {
if (!diff) {
console.log("diff not found");
return;
}
let tempDifRem = [];
tempDifRem = diff.getRemoveIds();
let tempDifAdd = [];
tempDifAdd = diff.getAddedIds();
for (let i = 0; i < tempDifAdd.length; ++i) {
privateRoot.add(tempDifAdd[i]);
}
for (let j = 0; j < tempDifRem.length; ++j) {
privateRoot.remove(tempDifRem[j]);
}
}
}
Connections {
target: privateRoot;
function onGameMenuModelChanged() {
if (!privateRoot.gameMenuModel) {
return;
}
const comp = Qt.createComponent(privateRoot.gameMenuModel.view);
if (comp.status === Component.Ready) {
if (privateRoot.gameMenu) {
privateRoot.gameMenu.destroy()
}
privateRoot.gameMenu = comp.createObject(scene);
if (privateRoot.gameMenu === null) {
// Error Handling
console.log("Error creating object");
}
privateRoot.gameMenu.model = privateRoot.gameMenuModel;
} else if (comp.status === Component.Error) {
// Error Handling
console.log("Error loading component: " + privateRoot.gameMenuModel.view, comp.errorString());
}
}
}
}
}

View File

@ -0,0 +1,72 @@
import QtQuick
import ViewSolutionsModule
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Page {
id: store
property var model: null;
ColumnLayout {
anchors.fill: parent
ListView {
id: listView
Layout.fillHeight: true
Layout.fillWidth: true
model: store.model
delegate: delegateRow
Component {
id: delegateRow
Rectangle {
width: listView.width
height: 100
color: (itemId === store.model.currentLevel) ? "#ffaf2c": "#00000000"
Behavior on color {
ColorAnimation {
duration: 200
}
}
RowLayout {
anchors.fill: parent
Image {
id: img
fillMode: Image.PreserveAspectCrop
source: itemImage
Layout.fillHeight: true
Layout.preferredWidth: height * 2
}
Label {
text: itemName
Layout.fillHeight: true
}
Label {
text: itemDescription
Layout.fillWidth: true
Layout.fillHeight: true
}
Button {
text: qsTr("Select");
visible: itemId !== store.model.currentLevel
onClicked: () => {
if (store.model)
store.model.select(itemId);
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,94 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick.Controls.Material
import QtQuick.Controls
import QtQuick.Layouts
Item {
id: settingsView
property var model: null
function save() {
if (!model) {
return;
}
model.setPort(port.value);
model.setHost(host.text);
model.setTheme(themeBox.currentIndex);
}
function reset() {
if (!model) {
return;
}
model.toDefault();
}
function update() {
if (!model) {
return;
}
model.forceUpdate();
}
GridLayout {
id: columnLayout
rows: 4
columns: 2
anchors.fill: parent
Label {
text: qsTr("Use Them")
Layout.fillWidth: true
}
ComboBox {
id: themeBox;
Layout.fillWidth: true
focusPolicy: Qt.NoFocus
model: [qsTr("Light"), qsTr("Dark")];
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
currentIndex: (settingsView.model)? settingsView.model.theme: 0
onCurrentIndexChanged: {
if (((settingsView.model)? settingsView.model.theme: 0)
!== currentIndex) {
themeWarning.visible = true;
}
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
}
Label {
id: themeWarning
text: qsTr("In order for the new theme to take effect, you need to reload the game.");
color: "#FF0000"
wrapMode: Label.WordWrap
Layout.maximumWidth: themeBox.width
visible: false;
}
}
}

View File

@ -0,0 +1,12 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
GraphicItem {
}

View File

@ -0,0 +1,64 @@
import QtQuick
import ViewSolutionsModule
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
Page {
id: store
property var model: null;
ColumnLayout {
anchors.fill: parent
ListView {
id: listView
Layout.fillHeight: true
Layout.fillWidth: true
model: store.model
delegate: delegateRow
Component {
id: delegateRow
RowLayout {
width: listView.width
height: 100
Image {
id: img
fillMode: Image.PreserveAspectCrop
source: itemImage
Layout.fillHeight: true
Layout.preferredWidth: height * 2
}
Label {
text: itemName
Layout.fillHeight: true
}
Label {
text: itemDescription
Layout.fillWidth: true
Layout.fillHeight: true
}
CheckBox {
id: buyStatus
tristate: false
checkState: (itemWasBuy)? Qt.Checked: Qt.Unchecked
enabled: false
}
Button {
text: qsTr("Buy");
visible: !itemWasBuy
onClicked: () => {
if (store.model)
store.model.buy(itemId);
}
}
}
}
}
}
}

View File

@ -0,0 +1,22 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick3D
import QtQuick3D.Particles3D
TargetDirection3D {
property var model: null
property string path: ""
position: (model)? model.velosityTargetPosition : Qt.vector3d(0, 0, 0)
normalized: (model)? model.velosityNormalized : false
magnitude: (model)? model.velosityMagnitude : 1
magnitudeVariation: (model)? model.velosityMagnitudeVariation : 0
positionVariation: (model)? model.velosityTargetPositionVariation : Qt.vector3d(0, 0, 0)
}

View File

@ -0,0 +1,18 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick3D
import QtQuick3D.Particles3D
VectorDirection3D {
property var model: null
property string path: ""
direction: (model)? model.velosityDirection : Qt.vector3d(0, 0, 0)
directionVariation: (model)? model.velosityDirectionValatility : Qt.vector3d(0, 0, 0)
}

View File

@ -0,0 +1,17 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick3D
import QtQuick3D.Particles3D
ParticleEffect {
PointLight {
brightness: (model)? Math.sqrt(model.fireStrength): 0;
color: (model)? model.color: "#ffffff";
}
}

View File

@ -0,0 +1,27 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick3D
import QtQuick3D.Particles3D
SpriteParticle3D {
id: particleFire
sprite: Texture {
source: "qrc:/CrawlCoreAssets/particles/sphere.png"
}
colorTable: Texture {
source: "qrc:/CrawlCoreAssets/particles/fireColorTable.png"
}
maxAmount: 300
color: "#ffffff"
colorVariation: Qt.vector4d(0.0, 0.6, 0.8, 0.0)
billboard: true
blendMode: SpriteParticle3D.Screen
fadeInDuration: 100
}

View File

@ -0,0 +1,114 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick3D
import QtQuick3D.Particles3D
ParticleEmitter3D {
id: root
property var model: null
property int guiId: (model) ? model.guiId : -1;
rotation: (model)? model.rotation: Qt.quaternion(0, 0, 0, 0)
scale: (model)? model.size: Qt.vector3d(0, 0, 0);
position: (model) ? model.position: Qt.vector3d(0,0,0);
visible: (model)? model.visible: false
depthBias: (model)? model.depthBias: 0
emitRate: (model)? model.emitRate: 0
enabled: (model)? model.enabled: true
lifeSpan: (model)? model.lifeSpan: 0
lifeSpanVariation: (model)? model.lifeSpanVariation: 0
particleEndScale: (model)? model.particleEndScale: 0
particleRotation: (model)? model.particleRotation: Qt.vector3d(0, 0, 0)
particleRotationVariation: (model)? model.particleRotationVariation: Qt.vector3d(0, 0, 0)
particleRotationVelocity: (model)? model.particleRotationVelocity: Qt.vector3d(0, 0, 0)
particleRotationVelocityVariation: (model)? model.particleRotationVelocityVariation: Qt.vector3d(0, 0, 0)
particleScaleVariation: (model)? model.particleScaleVariation: 0
onModelChanged: () => {
if (root.model) {
root.model.viewObject = root;
}
}
Item {
id: privateRoot
property var velosity: (model)? model.velocity: null
property string delegate: (model)? model.particleDelegate: ""
property string particleShape: (model)? model.particleShape: ""
property var view: null
onVelosityChanged: () => {
if (!root.model)
return;
const objModel = root.model.velocity;
if (!objModel) {
if (view) {
view.distory();
}
root.velocity = view = null;
return;
}
const viewTemplate = objModel.viewTemplate;
if (!view || (view.path !== viewTemplate)) {
let temp = Qt.createComponent(viewTemplate)
if (!temp)
return
if (temp.status === Component.Ready) {
let obj = temp.createObject(root)
obj.model = objModel;
if (view) {
view.distory();
}
root.velocity = view = obj;
} else {
console.log("wrong path (viewTemplate property) ot thq velosity module " + temp.errorString());
}
}
}
onDelegateChanged: () => {
let temp = Qt.createComponent(privateRoot.delegate)
if (!temp)
return
if (temp.status === Component.Ready) {
root.particle = temp.createObject(root.parent);
} else {
console.log("wrong path to the in model " + temp.errorString());
}
}
onParticleShapeChanged: () => {
let temp = Qt.createComponent(privateRoot.particleShape)
if (!temp)
return
if (temp.status === Component.Ready) {
root.shape = temp.createObject(root.parent);
} else {
console.log("wrong viewTemplate in model " + temp.errorString());
}
}
}
}

View File

@ -0,0 +1,39 @@
//#
//# Copyright (C) 2021-2021 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
import QtQuick
import QtQuick3D
import QtQuick3D.Particles3D
Gravity3D {
property var model: null
property int guiId: (model) ? model.guiId : -1;
enabled: (model)? model.enabled: false
magnitude: (model)? model.magnitude: 0
direction: (model)? model.direction: Qt.vector3d(0, 0, 0)
Behavior on magnitude {
NumberAnimation {
duration: 5000
easing.type: Easing.InQuad
}
}
Behavior on direction {
Vector3dAnimation {
duration: 5000
easing.type: Easing.InQuad
}
}
}

View File

@ -0,0 +1,6 @@
module CrawlModule
Crawl 1.0 Crawl.qml
DefaultMenu 1.0 DefaultMenu.qml
GraphicItem 1.0 GraphicItem.qml
ParticleEffect 1.0 ParticleEffect.qml
Light 1.0 Light.qml

View File

@ -0,0 +1,242 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "engine.h"
#include <QQmlComponent>
#include <ButterflyEngine/core/guiobject.h>
#include <ButterflyEngine/interfaces/ipreviewscaneworld.h>
#include "ButterflyEngine/interfaces/iworld.h"
#include <QThread>
#include <quasarapp.h>
#include "QDateTime"
#include "store.h"
namespace ButterflyEngine {
Engine::Engine(QObject *parent): QObject(parent) {
_store = new Store();
setNewUser(new User());
}
Engine::~Engine() {
for (auto it = _availableLvls.begin(); it != _availableLvls.end(); ++it) {
delete it.value();
}
_availableLvls.clear();
delete _currentUser;
}
QObject *Engine::scane() {
return _scane;
}
void Engine::setLevel(ILevel *world) {
if (_currentLevel == world)
return ;
if (_currentLevel) {
_currentLevel->reset();
}
_currentLevel = world;
emit worldChanged();
if (!_currentLevel) {
QuasarAppUtils::Params::log("Failed to init world. The World object is null! ",
QuasarAppUtils::Error);
_currentLevel = nullptr;
return;
}
if (!_currentLevel->world()) {
QuasarAppUtils::Params::log("Failed to init world. The World Object is null: ",
QuasarAppUtils::Error);
_currentLevel = nullptr;
return;
}
if (!_currentLevel->previewScane()) {
QuasarAppUtils::Params::log("Failed to init world. The World Preview scane is null. World Name: " +
_currentLevel->world()->itemName(),
QuasarAppUtils::Error);
_currentLevel = nullptr;
return;
}
connect(_currentLevel->previewScane(), &IPreviewScaneWorld::sigPrepareIsFinished,
this, &Engine::start);
connect(_currentLevel->world(), &IPreviewScaneWorld::sigGameFinished,
this, &Engine::stop);
_currentLevel->previewScane()->start({});
}
void Engine::setScane(QObject *newScane) {
if (_scane == newScane)
return;
_scane = newScane;
emit scaneChanged();
}
QObject *Engine::player() const {
if (_currentLevel && _currentLevel->world())
return _currentLevel->world()->player();
return nullptr;
}
QObject *Engine::world() const {
if (!_currentLevel)
return nullptr;
return _currentLevel->world();
}
void Engine::start(const StartData& config) const {
if (!_currentLevel)
return;
if (!_currentLevel->previewScane()->stop()) {
return;
}
_currentLevel->world()->start(config);
}
void Engine::stop() const {
if (!_currentLevel)
return;
_currentLevel->previewScane()->start(_currentLevel->previewScane()->configuration());
}
void Engine::handleUnlockedItem(int item) {
_store->buy(*_currentUser, item);
}
void Engine::handleDroppedItem(int ) {
}
void Engine::handleUnlockedItemsListChanged(const QSet<int> &newSet) {
}
void Engine::handleLevelChanged(int levelId) {
ILevel* data = _availableLvls.value(levelId, nullptr);
if (!data) {
QuasarAppUtils::Params::log("Failed to start lvl.", QuasarAppUtils::Error);
return;
}
setLevel(data);
}
ILevel *Engine::getLastLevel() {
for (const auto &data : qAsConst(_availableLvls)) {
if (data && data->world() && currentUser() &&
currentUser()->isUnlocked(data->world()->itemId())) {
return data;
}
}
return nullptr;
}
QObject *Engine::menu() const {
return _menu;
}
void Engine::setNewUser(User *user) {
if (_currentUser) {
disconnect(_currentUser, &User::sigUnlcoked, this, &Engine::handleUnlockedItem);
disconnect(_currentUser, &User::sigDropped, this, &Engine::handleDroppedItem);
disconnect(_currentUser, &User::sigUlockedItemsChanged,
this, &Engine::handleUnlockedItemsListChanged);
}
_currentUser = user;
static_cast<StoreViewModel*>(_menu->storeView())->setUser(_currentUser);
static_cast<AvailableLevelsModel*>(_menu->selectLevelModle())->setUser(_currentUser);
if (_currentUser) {
connect(_currentUser, &User::sigUnlcoked, this, &Engine::handleUnlockedItem);
connect(_currentUser, &User::sigDropped, this, &Engine::handleDroppedItem);
connect(_currentUser, &User::sigUlockedItemsChanged,
this, &Engine::handleUnlockedItemsListChanged);
}
}
void Engine::addLvl(ILevel *levelWordl) {
if (!levelWordl->world()) {
QuasarAppUtils::Params::log("The Level not contains world object!!!");
return;
}
_availableLvls.insert(levelWordl->world()->itemId(), levelWordl);
}
Store *Engine::store() const {
return _store;
}
QObject *Engine::nest() const {
if (!_currentLevel)
return nullptr;
return _currentLevel->previewScane();
}
User *Engine::currentUser() const {
return _currentUser;
}
void Engine::init() {
QMultiHash<int, const IItem *> availabelItems;
for (const auto &data : qAsConst(_availableLvls)) {
if (data && data->world())
availabelItems.unite(data->world()->childItemsRecursive());
}
_store->init(availabelItems);
static_cast<StoreViewModel*>(_menu->storeView())->init(_store, _currentUser);
QList<int> availableWorlds;
for (int id : _currentUser->unlockedItems()) {
auto item = availabelItems.value(id);
if (item->itemType() == IWorld::type()) {
availableWorlds.push_back(item->itemId());
}
}
#define selectedLevelModel static_cast<AvailableLevelsModel*>(_menu->selectLevelModle())
selectedLevelModel->setStore(_store);
selectedLevelModel->setKeys(availableWorlds);
connect(selectedLevelModel, &AvailableLevelsModel::sigUserSelectLevel,
this, &Engine::handleLevelChanged);
}
}

View File

@ -0,0 +1,179 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef ENGINE_H
#define ENGINE_H
#include <QFuture>
#include <QObject>
#include <QQmlEngine>
#include <ButterflyEngine/core/diff.h>
#include <ButterflyEngine/interfaces/ilevel.h>
namespace ButterflyEngine {
class IWorld;
class Store;
class StartData;
class User;
/**
* @brief The Engine class
*/
class Engine : public QObject {
Q_OBJECT
Q_PROPERTY(QObject* player READ player NOTIFY playerChanged)
Q_PROPERTY(QObject* world READ world NOTIFY worldChanged)
Q_PROPERTY(QObject* nest READ nest NOTIFY worldChanged)
Q_PROPERTY(QObject* scane READ scane WRITE setScane NOTIFY scaneChanged)
Q_PROPERTY(QObject * menu READ menu NOTIFY menuChanged)
public:
Engine(QObject * parent = nullptr);
~Engine();
/**
* @brief scane This method return main scane of the game.
* @return pointer to main game scane.
*/
Q_INVOKABLE QObject* scane();
/**
* @brief setLevel This method set new world level for game.
* @param world This is pointer to new world level.
*/
void setLevel(ILevel *world);
/**
* @brief setScane This method sets new scane object. The scane object are
* @param newScane are Qt Quick 3d node object form qml.
*/
void setScane(QObject *newScane);
/**
* @brief currentWorld return pointer to current world object.
* @return raw pointer to current world object.
*/
IWorld *currentWorld() const;
/**
* @brief player return player object.
* @return player object
*/
QObject* player() const;
/**
* @brief world return player object.
* @return world object
*/
QObject* world() const;
/**
* @brief currentUser This method return pointer to current user.
* @return pointer too current user.
*/
User *currentUser() const;
/**
* @brief init This method initialize the main model. Sets available levels and items.
* @param availabelItems This is list of available items.
*/
void init();
/**
* @brief store This pointer return pointer to store.
* @return pointer to store.
*/
Store *store() const;
/**
* @brief nest This method return pointer to the nest model.
* @return pointer to the nest model.
*/
QObject *nest() const ;
/**
* @brief menu This is a main menu model.
* @return main menu model object.
*/
QObject *menu() const;
/**
* @brief setNewUser This method will initialise the new user profile.
* @param user This is pointer to new user profile.
*/
void setNewUser(User* user);
/**
* @brief addLvl This method should be add level to game.
* @param levelWordl This is world instance
*/
void addLvl(ILevel* levelWordl);
signals:
void scaneChanged();
void playerChanged();
void worldChanged();
void menuChanged();
private slots:
/**
* @brief start This method run current lvl ( move prepared data from the nest to game world)
* @param config This is confuguration that created new game world.
* @return true if lvl started successful.
*/
void start(const StartData &config) const;
/**
* @brief stop This slots invoked when world finished own session.
*/
void stop() const;
/**
* @brief handleUnlockedItem This slot invoked when emited the User::unclokItem signal.
* @param item This is id of the unlocked item
*/
void handleUnlockedItem(int item);
/**
* @brief handleUnlockedItem This slot invoked when emited the User::droppItem signal.
* @param item This is id of the dropped item
*/
void handleDroppedItem(int item);
/**
* @brief handleUnlockedItem This slot invoked when emited the User::setUnlockedItems signal.
* @param item This is new list of the unclod items.
*/
void handleUnlockedItemsListChanged(const QSet<int>& newSet);
/**
* @brief handleLevelChanged This slot invoked when user select new level.
* @param levelId level id
*/
void handleLevelChanged(int levelId);
private:
ILevel * getLastLevel();
void renderLoop();
QObject *_menu = nullptr;
QObject *_scane = nullptr;
ILevel* _currentLevel = nullptr;
QHash<int, ILevel*> _availableLvls;
User *_currentUser = nullptr;
Store *_store = nullptr;
};
}
#endif // ENGINE_H

View File

@ -0,0 +1,118 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "eventserver.h"
#include <QDateTime>
#include <thread>
#include <QtConcurrent>
#include <ButterflyEngine/interfaces/iworlditem.h>
#include <ButterflyEngine/interfaces/iworld.h>
namespace ButterflyEngine {
EventServer::EventServer(IWorld *instance) {
debug_assert(instance, "Invalid World pointer in EventServer");
_worldInstance = instance;
_supportedGameEventsKeys = {GameEvents::Intersects};
}
EventServer::~EventServer() {
stop();
}
void EventServer::start() {
if (_renderLoopFuture.isRunning())
return;
_renderLoop = true;
_renderLoopFuture = QtConcurrent::run([this](){renderLoop();});
}
void EventServer::stop() {
_renderLoop = false;
_renderLoopFuture.waitForFinished();
}
void EventServer::handleAvailableObjectChanges(const Diff &diff) {
for (int added: diff.addedIds) {
auto obj = _worldInstance->getItem(added);
if (obj->isDecorative()) {
continue;
}
for (int event: qAsConst(_supportedGameEventsKeys)) {
addToSupportedGameEvents(obj, event);
}
_objects.insert(obj->guiId(), obj);
}
for (int removed: diff.removeIds) {
for (int event: qAsConst(_supportedGameEventsKeys)) {
_supportedGameEvents[event].remove(removed);
}
_objects.remove(removed);
}
}
void EventServer::eventProcess() {
for (auto it = _supportedGameEvents.begin(); it != _supportedGameEvents.end(); ++it) {
for (const IWorldItem* item : qAsConst(it.value())) {
switch (it.key()) {
case GameEvents::Intersects : {
QList<const IWorldItem*> result;
for (const IWorldItem *object : qAsConst(_objects)) {
if (item != object && item->intersects(*object)) {
result.append(object);
}
}
if (result.size()) {
emit sigIntersect(item, result);
}
break;
}
default: {
QuasarAppUtils::Params::log("Not supported event", QuasarAppUtils::Error);
}
}
}
}
}
void EventServer::addToSupportedGameEvents(const IWorldItem * obj, int event) {
if (obj->isSopportEvent(event)) {
_supportedGameEvents[event].insert(obj->guiId(), obj);
};
}
void EventServer::renderLoop() {
while (_renderLoop) {
quint64 currentTime = QDateTime::currentMSecsSinceEpoch();
if (!_oldTimeRender) {
_oldTimeRender = currentTime;
continue;
}
eventProcess();
int waitTime = 100 - currentTime + _oldTimeRender;
_oldTimeRender = currentTime;
if (waitTime > 0)
std::this_thread::sleep_for(std::chrono::milliseconds(waitTime));
}
}
}

View File

@ -0,0 +1,77 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include <QFuture>
#include <QObject>
#include <ButterflyEngine/core/diff.h>
#include <QMultiHash>
#ifndef EVENTSERVER_H
#define EVENTSERVER_H
namespace ButterflyEngine {
class IWorldItem;
class IWorld;
/**
* @brief The EventServer class process all game events.
* This class process all game events on the separate thread and do not change the game objects. All signal of the events return constant object pointers.
*/
class EventServer: public QObject
{
Q_OBJECT
public:
EventServer(IWorld * instance);
~EventServer();
/**
* @brief start This method start a processing og the objects events.
*/
void start();
/**
* @brief stop This method stop the processing of the objects.
*/
void stop();
public slots:
/**
* @brief handleAvailableObjectChanges This slots handle all changes of the world.
* @param diff This is changes on the world.
*/
void handleAvailableObjectChanges(const Diff& diff);
signals:
/**
* @brief sigIntersect This signal emit when objects intersect on the world.
* @param trigger This is pointer to object that support this evvent.
* @param objects This is list of the intersects objects.
*/
void sigIntersect(const IWorldItem* trigger, QList<const IWorldItem*> objects);
private:
void eventProcess();
void addToSupportedGameEvents(const IWorldItem *obj, int event);
void renderLoop();
IWorld * _worldInstance = nullptr;
QHash<int, const IWorldItem*> _objects;
QHash<int, QHash<int, const IWorldItem*>> _supportedGameEvents;
QList<int> _supportedGameEventsKeys;
QFuture<void> _renderLoopFuture;
bool _renderLoop = false;
quint64 _oldTimeRender = 0;
};
}
#endif // EVENTSERVER_H

View File

@ -0,0 +1,42 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "pluginloader.h"
#include <QLibrary>
#include <quasarapp.h>
typedef IWorld* (*worldInstance)();
PluginLoader::PluginLoader() {
}
IWorld* PluginLoader::load(const QString &pluginPath) {
QLibrary lib(pluginPath);
if (!lib.load()) {
QuasarAppUtils::Params::log("Fail to load game module. Message: " + lib.errorString(),
QuasarAppUtils::Error);
return nullptr;
}
worldInstance worldFunc = (worldInstance)lib.resolve("worldInstance");
if (!worldFunc) {
QuasarAppUtils::Params::log("Fail to load game module."
" Message: Failed to find a instance function in the %0 module",
QuasarAppUtils::Error);
lib.unload();
return nullptr;
}
return worldFunc();
}

View File

@ -0,0 +1,31 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef PLUGINLOADER_H
#define PLUGINLOADER_H
#include <QString>
class IWorld;
/**
* @brief The PluginLoader class This class load shared objects like a plugins.
*/
class PluginLoader {
public:
PluginLoader();
/**
* @brief load This method load a plugin game module.
* @param pluginPath Path to so or dll plugin file.
* @return Snake WorldInstance;
* @note The plugin shiold be implement instance function and if you youse Windows systems marked as a DLL_EXPORT symbol.
*/
static IWorld* load(const QString& pluginPath);
};
#endif // PLUGINLOADER_H

View File

@ -0,0 +1,8 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "settings.h"

View File

@ -0,0 +1,16 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef SNAKESETTINGS_H
#define SNAKESETTINGS_H
#include <quasarapp.h>
#define THEME "THEME_GUI"
#define THEME_DEFAULT 0
using Settings = QuasarAppUtils::Settings;
#endif // SNAKESETTINGS_H

View File

@ -0,0 +1,54 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "store.h"
#include <ButterflyEngine/interfaces//iitem.h>
namespace ButterflyEngine {
Store::Store()
{
}
bool Store::buy(User &buyer, int itemId) {
auto item = getItemById(itemId);
if (buyer.getTier() < item->requiredTier()) {
return false;
}
if (buyer.getMoney() < item->cost()) {
return false;
}
buyer.setMoney(buyer.getMoney() - item->cost());
buyer.unclokItem(itemId);
return true;
}
bool Store::init(const QMultiHash<int, const IItem *> &availabelItems) {
_store = availabelItems;
return true;
}
const IItem *Store::getItemById(int id) const {
return _store.value(id, nullptr);
}
int Store::size() const {
return _store.size();
}
QList<int> Store::keysList() const {
return QList<int>{_store.keyBegin(), _store.keyEnd()};
}
}

View File

@ -0,0 +1,64 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef STORE_H
#define STORE_H
#include "user.h"
namespace ButterflyEngine {
class IItem;
/**
* @brief The Store class contains method for control all game items beetwin users.
*/
class Store
{
public:
Store();
/**
* @brief buy This method unlock the item with @a itemId for @a buyer. The
* @param buyer This is user that will be buy item with @a itemId id.
* @param itemId This is id of the item that @a buyer will be buy
* @return true if the deal gas been completed successfully
*/
bool buy(User& buyer, int itemId);
/**
* @brief init This method initialise store of the game.
* @param availabelItems This is hash of the available item.
* @return true if the items inited successfuly else false.
*/
bool init(const QMultiHash<int, const IItem *> &availabelItems);
/**
* @brief getItemById This method return item by id.
* @param id This is id of the required item.
* @return pointer to item. if The item with @a id not found then return nullptr.
*/
const IItem* getItemById(int id) const;
/**
* @brief size This method return count of the available items in store.
* @return count of the available items.
*/
int size() const;
/**
* @brief keysList This method return a list of available keys
* @return a list of available keys
*/
QList<int> keysList() const;
private:
QMultiHash<int, const IItem*> _store;
};
}
#endif // STORE_H

View File

@ -0,0 +1,124 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "user.h"
namespace ButterflyEngine {
constexpr float tierMul = 1.2;
constexpr int firstTierCount = 10;
/// @private
template <int N>
struct Tiers
{
enum { value = static_cast<const int>(tierMul * Tiers<N - 1>::value)};
};
/// @private
template <>
struct Tiers<0>
{
enum { value = 0 };
};
/// @private
template <>
struct Tiers<1>
{
enum { value = firstTierCount };
};
// End Tiers table
constexpr int maximumTear = 100;
#define T(X) Tiers<X>::value
constexpr int tiersTable[maximumTear] = {T(0), T(1), T(2), T(3), T(4), T(5), T(6), T(7), T(8), T(9),
T(10), T(11), T(12), T(13), T(14), T(15), T(16), T(17), T(18), T(19),
T(20), T(21), T(22), T(23), T(24), T(25), T(26), T(27), T(28), T(29),
T(30), T(31), T(32), T(33), T(34), T(35), T(36), T(37), T(38), T(39),
T(40), T(41), T(42), T(43), T(44), T(45), T(46), T(47), T(48), T(49),
T(50), T(51), T(52), T(53), T(54), T(55), T(56), T(57), T(58), T(59),
T(60), T(61), T(62), T(63), T(64), T(65), T(66), T(67), T(68), T(69),
T(70), T(71), T(72), T(73), T(74), T(75), T(76), T(77), T(78), T(79),
T(80), T(81), T(82), T(83), T(84), T(85), T(86), T(87), T(88), T(89),
T(90), T(91), T(92), T(93), T(94), T(95), T(96), T(97), T(98), T(99)};
User::User() {
}
const QSet<int> &User::unlockedItems() const {
return _unlockedItems;
}
bool User::isUnlocked(int item) const {
return _unlockedItems.contains(item);
}
void User::unclokItem(int item) {
_unlockedItems.insert(item);
emit sigUnlcoked(item);
}
void User::droppItem(int item) {
_unlockedItems.remove(item);
emit sigDropped(item);
}
void User::setUnlockedItems(const QSet<int> &newUnlockedItems) {
_unlockedItems = newUnlockedItems;
emit sigUlockedItemsChanged(newUnlockedItems);
}
int User::recalcTier() {
int _tier = 0;
while (getXp() > tiersTable[_tier]) {
_tier++;
}
return _tier;
}
void User::setTier(int tier) {
if (_tier == tier)
return;
_tier = tier;
emit tierChanged();
}
int User::getXp() const {
return _xp;
}
void User::setXp(int newXp) {
if (_xp == newXp)
return;
_xp = newXp;
setTier(recalcTier());
emit xpChanged();
}
int User::getTier() {
return _tier;
}
int User::getMoney() const {
return _money;
}
void User::setMoney(int newMoney) {
if (_money == newMoney)
return;
_money = newMoney;
emit moneyChanged();
}
}

View File

@ -0,0 +1,192 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include <QSet>
#include <QObject>
#ifndef USER_H
#define USER_H
namespace ButterflyEngine {
/**
* @brief The User class This is internal class for collection all user data and user state.
*/
class User : public QObject
{
Q_OBJECT
/**
* @brief money This current user money count. An user can buy and sell game items using own money amount.
* @see User::setMoney
* @see User::getMoney
*/
Q_PROPERTY(int money READ getMoney WRITE setMoney NOTIFY moneyChanged)
/**
* @brief xp This is experience count of an user. The experience unlock new tiers and make available new items for buying.
* @see User::setXp
* @see User::getXp
* @see User::tier
* @see User::getTier
*/
Q_PROPERTY(int xp READ getXp WRITE setXp NOTIFY xpChanged)
/**
* @brief tier This us user tier. This value automaticaly generated by cuuren user experience count.
* @see User::xp
* @see User::getXp
* @see User::getTier
*/
Q_PROPERTY(int tier READ getTier NOTIFY tierChanged)
public:
User();
/**
* @brief getMoney This current user money count. An user can buy and sell game items using own money amount.
* @return current value of the User::money property
* @see User::setMoney
* @see User::money
*/
int getMoney() const;
/**
* @brief setMoney This method sets new value of the user money amount.
* @param newMoney this is new value of users money.
* @see User::getMoney
* @see User::money
*/
void setMoney(int newMoney);
/**
* @brief getXp This is experience count of an user. The experience unlock new tiers and make available new items for buying.
* @return current user xpereans.
* @see User::setXp
* @see User::getXp
* @see User::tier
* @see User::getTier
*/
int getXp() const;
/**
* @brief setXp This method sets new value of the user experience.
* @param newXp This is new value of the users experience.
* @note This method can be change the User::tier property
* @see User::xp
* @see User::getXp
* @see User::tier
* @see User::getTier
*/
void setXp(int newXp);
/**
* @brief getTier This us user tier. This value automaticaly generated by cuuren user experience count.
* @return current value of the users tier.
* @see User::xp
* @see User::getXp
* @see User::tier
*/
int getTier();
/**
* @brief unlockedItems This method return set of the unlocked items of this user.
* @return Set of the unlocked items of this user.
* @see User::unclokItem
* @see User::unlockedItems
* @see User::droppItem
* @see User::isUnlocked
* @see User::setUnlockedItems
*/
const QSet<int> &unlockedItems() const;
/**
* @brief isUnlocked This method check if the @a item is unlocked for this user.
* @param item This is id of the checked item.
* @return true if the item is uncloked else false.
* @see User::unclokItem
* @see User::unlockedItems
* @see User::droppItem
* @see User::isUnlocked
* @see User::setUnlockedItems
*/
bool isUnlocked(int item) const;
/**
* @brief unclokItem This method unclok the @a item for current user.
* @param item This is id of item that need to unclok.
* @see User::unclokItem
* @see User::unlockedItems
* @see User::droppItem
* @see User::isUnlocked
* @see User::setUnlockedItems
*/
void unclokItem(int item);
/**
* @brief droppItem This method dropp item from user.
* @param item This is id of the dropped item
* @see User::unclokItem
* @see User::unlockedItems
* @see User::droppItem
* @see User::isUnlocked
* @see User::setUnlockedItems
*/
void droppItem(int item);
signals:
void moneyChanged();
void tierChanged();
void xpChanged();
/**
* @brief sigUlockedItemsChanged This signal emited when users list of unclode items is changed..
* @param unclokedItems This is unlocked items set. Each items in the set is id of the unclocked item.
*/
void sigUlockedItemsChanged(const QSet<int> & unclokedItems);
/**
* @brief sigUnlcoked This signal emmited when user unlock one item.
* @param item This is unlocked item id.
* @see User::unclokItem
*/
void sigUnlcoked(int item);
/**
* @brief sigDropped This signal emmited when user dropped one item.
* @param item This is dpopped item id.
* @see User::droppItem
*/
void sigDropped(int item);
protected:
/**
* @brief setUnlockedItems This method sets new set of uncloked items
* @param newUnlockedItems This is new set of the uncloked items
* @see User::unclokItem
* @see User::unlockedItems
* @see User::droppItem
* @see User::isUnlocked
* @see User::setUnlockedItems
*/
void setUnlockedItems(const QSet<int> &newUnlockedItems);
private:
int recalcTier();
void setTier(int tier);
int _money = 0;
int _xp = 0;
int _tier = 0;
QSet<int> _unlockedItems;
};
}
#endif // USER_H

View File

@ -0,0 +1,9 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "worldstatus.h"

View File

@ -0,0 +1,35 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef WORLDSTATUS_H
#define WORLDSTATUS_H
#include <QObject>
/**
* @brief The WorldStatus enum This enum contains statuses of the world.
* @note This statuses available only internal in main engine library.
*/
namespace WorldStatus
{
Q_NAMESPACE // required for meta object creation
/**
* @brief The WorldStatus enum This enum contains statuses of the world.
* @note This statuses available only internal in main engine library.
*/
enum Status {
/// Undefined status. Using by default
Undefined = 0,
/// World with this status emit random control signals for the player object fir emulate game session of the AI.
Background,
/// World with this status show hame control menu and listem player signals.
Game
};
Q_ENUM_NS(Status) // register the enum in meta object data
}
#endif // WORLDSTATUS_H

View File

@ -16,7 +16,7 @@ bool init() {
} }
QString version() { QString version() {
return ButterflyEngine_VERSION; return BUTTERFLY_ENGINE_VERSION;
} }

View File

@ -16,12 +16,12 @@ namespace ButterflyEngine {
* @brief init main initialize method of The ButterflyEngine library * @brief init main initialize method of The ButterflyEngine library
* @return true if library initialized successfull * @return true if library initialized successfull
*/ */
bool ButterflyEngine_EXPORT init(); bool BUTTERFLY_ENGINE_EXPORT init();
/** /**
* @brief version This method return string value of a library version * @brief version This method return string value of a library version
* @return string value of a library version * @return string value of a library version
*/ */
QString ButterflyEngine_EXPORT version(); QString BUTTERFLY_ENGINE_EXPORT version();
}; };

View File

@ -0,0 +1,110 @@
# Extension concept
The extension it is separate module class with custom function.
## How to use
1. Create own child class from IRender interface.
2. Override the IRender::render method of base interface
3. Check compatibility betwin this type and requred type using the IRender::checkminimumRequariedType method.
4. In the render method using dynamic_cast operator get neede interface of class object.
5. Implement needed functions for object.
## Example:
Movable object header:
```cpp
class CRAWL_EXPORT MovableObject: public virtual IRender
{
public:
MovableObject();
void render(unsigned int tbfMsec) override;
const QVector3D &movableVector() const;
void setMovableVector(const QVector3D &newMovableVector);
float angularVelocity() const;
void setAngularVelocity(float newAngularVelocity);
float breakingForce() const;
void setBreakingForce(float newBreakingForce);
private:
QVector3D _movableVector;
QVector3D _currentMovableVector;
float _angularVelocity = 0;
float _breakingForce = 0;
};
```
Movable object source:
```cpp
MovableObject::MovableObject()
{
}
void MovableObject::render(unsigned int tbfMsec) {
auto _this = checkminimumRequariedType<IWorldItem>();
// get object center position
QVector3D currentPosition = _this->position();
// move object to vector
currentPosition += (_currentMovableVector * (tbfMsec / 1000.0));
_this->setposition(currentPosition);
// calc temp vector betvin user moveble vector and real moveble vector
QVector3D tempVector = _movableVector - _currentMovableVector ;
// calc change on this iteration for new moveble vector
float delta = std::min(_angularVelocity * (tbfMsec / 1000.0), static_cast<double>(tempVector.length()));
// resize temp vector for calc changes of the movableVector
tempVector = tempVector.normalized() * delta;
// recalc new currentMovable vector (applay changes)
_currentMovableVector += tempVector;
float newMovableVectorLength = std::max(_movableVector.length() - (_breakingForce * (tbfMsec / 1000.0)), 0.0);
// update movable vector
_movableVector = _movableVector.normalized() * newMovableVectorLength;
}
const QVector3D &MovableObject::movableVector() const {
return _movableVector;
}
void MovableObject::setMovableVector(const QVector3D &newMovableVector) {
_movableVector = newMovableVector;
}
float MovableObject::angularVelocity() const {
return _angularVelocity;
}
void MovableObject::setAngularVelocity(float newAngularVelocity) {
_angularVelocity = newAngularVelocity;
}
float MovableObject::breakingForce() const {
return _breakingForce;
}
void MovableObject::setBreakingForce(float newBreakingForce) {
_breakingForce = newBreakingForce;
}
```

View File

@ -0,0 +1,41 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "autogenerateclaster.h"
#include "params.h"
namespace ButterflyEngine {
AutoGenerateClaster::AutoGenerateClaster() {
}
void AutoGenerateClaster::generateItems() {
for (unsigned int count = itemsCount(); count > 0; count--) {
if (!_factory) {
QuasarAppUtils::Params::log("Please use the registerItemType method"
" before invoke parent constructor.",
QuasarAppUtils::Error);
return;
}
add(factory());
}
}
ClasterItem *AutoGenerateClaster::factory() const {
if (!_factory) {
QuasarAppUtils::Params::log("Please use the registerBodyitem method"
" before invoke parent constructor.",
QuasarAppUtils::Error);
return nullptr;
}
return _factory();
}
}

View File

@ -0,0 +1,65 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef AUTOGENERATECLASTER_H
#define AUTOGENERATECLASTER_H
#include "claster.h"
namespace ButterflyEngine {
/**
* @brief The AutoGenerateClaster class hs support the registration default claster item class and factory method for the items.
*/
class BUTTERFLY_ENGINE_EXPORT AutoGenerateClaster: public Claster
{
public:
AutoGenerateClaster();
/**
* @brief itemsCount This method sould be return count of the registered items on the claster object.
* @return items count of the child objects.
*/
virtual unsigned int itemsCount() const = 0;
template<class Type>
/**
* @brief registerItemType This method register claster item type. Items will be generated in the generateItems method. The size of body companents calc from the itemsCount property.
*/
void registerItemType() {
_factory = [](){
return new Type;
};
}
protected:
/**
* @brief generateItems This method invoked after iit object on the world and generate list of the default claster items.
* @note This method should be invked after initialized of this object.
*/
virtual void generateItems();
/**
* @brief factory This method create new item of the claster. See the registerItemType for get more information.
* @return return new item of the claster item. If the object not registered return nullptr.
*/
ClasterItem *factory() const;
/**
* @brief isClasterItemRegistered
* @return tru if the class is registered.
*/
bool isClasterItemRegistered() const;
private:
std::function<ClasterItem*()> _factory = nullptr;
};
}
#endif // AUTOGENERATECLASTER_H

View File

@ -0,0 +1,31 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "basemotion.h"
namespace ButterflyEngine {
BaseMotion::BaseMotion() {
}
const QQuaternion &BaseMotion::staticRotation() const {
return _staticRotation;
}
void BaseMotion::setStaticRotation(const QQuaternion &newStaticRotation) {
_staticRotation = newStaticRotation;
}
void BaseMotion::render(unsigned int tbfMsec) {
if (auto _this = checkminimumRequariedType<GuiObject>()) {
renderPosition(_this, tbfMsec);
renderRotation(_this, tbfMsec);
}
}
}

View File

@ -0,0 +1,72 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef BASEMOTION_H
#define BASEMOTION_H
#include "ButterflyEngine/interfaces/irender.h"
#include <QQuaternion>
namespace ButterflyEngine {
class GuiObject;
/**
* @brief The BaseMotion class contains base functions of the motion.
* For Create your own motion alghoritm you need to override two methods:
* * renderPosition
* * renderRotation
*
*/
class BUTTERFLY_ENGINE_EXPORT BaseMotion : public virtual IRender
{
public:
BaseMotion();
// IRender interface
public:
void render(unsigned int tbfMsec);
/**
* @brief staticRotation This method retur nstatic rotation in quaternion. The static rotation rotate object to setted value independet then movable vector.
* @return quterion of the static rotation
*/
const QQuaternion &staticRotation() const;
/**
* @brief setStaticRotation This metho sets new value of the static rotation of this object.
* @param newStaticRotation new value of the static rotation.
* @note if you want use eilor angles then use the QQuaternion::fromEulerAngles method.
* @note See the staticRotation method for get more information.
*/
void setStaticRotation(const QQuaternion &newStaticRotation);
protected:
/**
* @brief renderRotation This method recalc raration for an @a object. The Default do nothing.
* @param object This is provessing object. Usually @a an object is casted pointer of this to GuiObject type.
* @param tbfMsec This is time betwin frames argument. soame as in the IRender::render function.
*/
virtual void renderRotation(GuiObject* object, unsigned int tbfMsec) = 0;
/**
* @brief renderRotation This method recalc position for an @a object.
* @param object This is provessing object. Usually @a an object is casted pointer of this to GuiObject type.
* @param tbfMsec This is time betwin frames argument. soame as in the IRender::render function.
*/
virtual void renderPosition(GuiObject* object, unsigned int tbfMsec) = 0;
private:
QQuaternion _staticRotation = QQuaternion::fromEulerAngles(0,0,0);
};
}
#endif // BASEMOTION_H

View File

@ -0,0 +1,77 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "circularmotion.h"
#include <ButterflyEngine/core/guiobject.h>
#include "cmath"
namespace ButterflyEngine {
CircularMotion::CircularMotion(const QVector3D *center) {
_center = center;
}
void CircularMotion::render(unsigned int tbfMsec) {
if (auto _this = checkminimumRequariedType<GuiObject>()) {
renderPosition(_this, tbfMsec);
renderRotation(_this, tbfMsec);
}
}
float CircularMotion::angularVelocity() const {
return _angularVelocity;
}
void CircularMotion::setAngularVelocity(float newAngularVelocity) {
_angularVelocity = newAngularVelocity;
}
const QVector3D &CircularMotion::axis() const {
return _axis;
}
void CircularMotion::setAxis(const QVector3D &newAxis) {
_axis = newAxis;
}
float CircularMotion::radius() const {
return _radius;
}
void CircularMotion::setRadius(float newRadius) {
_radius = newRadius;
}
double CircularMotion::anglePosition() const {
return _angle;
}
void CircularMotion::setAnglePosition(double newAngle) {
_angle = newAngle;
}
void CircularMotion::renderRotation(GuiObject *object,
unsigned int ) {
object->setRotation(QQuaternion::rotationTo({1.0f, 0.0, 0.0}, *_center) * staticRotation());
}
void CircularMotion::renderPosition(GuiObject *object,
unsigned int tbfMsec) {
if (!_center)
return;
double motionCoef = 360 / (2 * M_PI * radius());
_angle += motionCoef * angularVelocity() * (tbfMsec / 1000.f);
auto normal = (QQuaternion::fromAxisAndAngle(_axis, _angle) * QVector3D{0,0,1}).normalized();
object->setposition(*_center + normal * radius());
}
}

View File

@ -0,0 +1,106 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef CIRCULARMOTION_H
#define CIRCULARMOTION_H
#include <ButterflyEngine/components/basemotion.h>
#include <QVector3D>
namespace ButterflyEngine {
class GuiObject;
/**
* @brief The CircularMotion class. This class contains render function for the moving guiobject by round.
* @note For motion set motion asix and angular velocity
*/
class BUTTERFLY_ENGINE_EXPORT CircularMotion: public BaseMotion
{
public:
CircularMotion(const QVector3D* center);
// IRender interface
public:
void render(unsigned int tbfMsec) override;
/**
* @brief angularVelocity This is property are speed of motion.
* @return current speed of the motion object.
*/
float angularVelocity() const;
/**
* @brief setAngularVelocity This method sets new value of the current speed of the object.
* @param newAngularVelocity This is new value of the motion speed
*/
void setAngularVelocity(float newAngularVelocity);
/**
* @brief axis This method are asix of motion. This object will moving around this axis.
* @return curretn asix value.
*/
const QVector3D &axis() const;
/**
* @brief setAxis This method sets new value of the motion axis.
* @param newAxis This is new value of the motion asix.
*/
void setAxis(const QVector3D &newAxis);
/**
* @brief radius This method return current radius of the circular motion
* @return current radius
*/
float radius() const;
/**
* @brief setRadius This method sets new value of the circular motion radius.
* @param newRadius This is new value of the circular motion radius.
*/
void setRadius(float newRadius);
/**
* @brief anglePosition This method return current angel of the item position arountd center.
* @return current angle position around center.
*/
double anglePosition() const;
/**
* @brief setAnglePosition This method sets new angel of the item position arountd center.
* @return newAngle angle position around center.
*/
void setAnglePosition(double newAngle);
protected:
/**
* @brief renderRotation This method recalc raration for an @a object. The Default implementation rotate object to center.
* @param object This is provessing object. Usually @a an object is casted pointer of this to GuiObject type.
* @param tbfMsec This is time betwin frames argument. soame as in the IRender::render function.
*/
void renderRotation(GuiObject* object, unsigned int) override;
/**
* @brief renderRotation This method recalc position for an @a object. The Default implementation move the current object around center.
* @param object This is provessing object. Usually @a an object is casted pointer of this to GuiObject type.
* @param tbfMsec This is time betwin frames argument. soame as in the IRender::render function.
*/
void renderPosition(GuiObject* object, unsigned int tbfMsec) override;
private:
float _angularVelocity = 0;
QVector3D _axis;
const QVector3D *_center = nullptr;
float _radius;
double _angle = 0;
};
}
#endif // CIRCULARMOTION_H

View File

@ -0,0 +1,42 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "claster.h"
#include <ButterflyEngine/core/clasteritem.h>
namespace ButterflyEngine {
Claster::Claster() {}
Claster::~Claster() {
for (auto child : qAsConst(_objects)) {
if (auto obj = dynamic_cast<ClasterItem*>(child))
obj->removeClaster(this);
}
}
void Claster::add(ClasterItem *object) {
_objects.insert(object->guiId(), object);
if (auto singlClasterObject = dynamic_cast<ClasterItem*>(object)) {
singlClasterObject->setClaster(this);
}
}
void Claster::remove(ClasterItem *object) {
_objects.remove(object->guiId());
}
void Claster::remove(int id) {
_objects.remove(id);
}
const QHash<int, ClasterItem *> &Claster::objects() const {
return _objects;
}
}

View File

@ -0,0 +1,63 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef CLASTER_H
#define CLASTER_H
#include "ButterflyEngine/global.h"
#include <QHash>
namespace ButterflyEngine {
class ClasterItem;
/**
* @brief The Claster class are object with support multiple objects render.
* For example snake with 20 points of the snake blocks.
* @note The claster object is extansion for the IWorldItems objects.
*/
class BUTTERFLY_ENGINE_EXPORT Claster
{
public:
Claster();
virtual ~Claster();
/**
* @brief add This method added new object to claster.
* @param object This is model of added object
* @note if you want you can override this methods for extend functionality of this class.
*/
virtual void add(ClasterItem* object);
/**
* @brief remove This method remove object from claster
* @param object poiter of removed object
*/
virtual void remove(ClasterItem* object);
/**
* @brief remove some as a Claster::remove(IWorldItem* object) but by id.
* @param id of the remved object.
*/
virtual void remove(int id);
/**
* @brief objects This method return list of collected objects.
* @return return const reference to objects list .
*/
const QHash<int, ClasterItem*> &objects() const;
private:
QHash<int, ClasterItem*> _objects;
};
}
#endif // CLASTER_H

View File

@ -0,0 +1,94 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "movableobject.h"
#include "ButterflyEngine/core/guiobject.h"
#include <math.h>
namespace ButterflyEngine {
MovableObject::MovableObject() {
}
void MovableObject::render(unsigned int tbfMsec) {
if (auto _this = checkminimumRequariedType<GuiObject>()) {
renderPosition(_this, tbfMsec);
renderRotation(_this, tbfMsec);
}
}
const QVector3D &MovableObject::movableVector() const {
return _movableVector;
}
void MovableObject::setMovableVector(const QVector3D &newMovableVector) {
_movableVector = newMovableVector;
}
float MovableObject::angularVelocity() const {
return _angularVelocity;
}
void MovableObject::setAngularVelocity(float newAngularVelocity) {
_angularVelocity = newAngularVelocity;
}
float MovableObject::breakingForce() const {
return _breakingForce;
}
void MovableObject::setBreakingForce(float newBreakingForce) {
_breakingForce = newBreakingForce;
}
void MovableObject::renderRotation(GuiObject *object, unsigned int) {
if (_currentMovableVector.length() > 0) {
object->setRotation(QQuaternion::rotationTo({1.0f, 0.0, 0.0}, _currentMovableVector) * staticRotation());
}
}
void MovableObject::renderPosition(GuiObject *object, unsigned int tbfMsec) {
// get object center position
QVector3D currentPosition = object->position();
// move object to vector
currentPosition += (_currentMovableVector * (tbfMsec / 1000.0));
object->setposition(currentPosition);
// calc temp vector betvin user moveble vector and real moveble vector
QVector3D tempVector = _movableVector - _currentMovableVector ;
// calc change on this iteration for new moveble vector
float delta = 0.0;
if (_angularVelocity <= 0) {
delta = tempVector.length();
} else {
delta = std::min(_angularVelocity * (tbfMsec / 1000.0), static_cast<double>(tempVector.length()));
}
// resize temp vector for calc changes of the movableVector
tempVector = tempVector.normalized() * delta;
// recalc new currentMovable vector (applay changes)
_currentMovableVector += tempVector;
float newMovableVectorLength = std::max(_movableVector.length() - (_breakingForce * (tbfMsec / 1000.0)), 0.0);
// update movable vector
_movableVector = _movableVector.normalized() * newMovableVectorLength;
}
const QVector3D &MovableObject::currentMovableVector() const {
return _currentMovableVector;
}
}

View File

@ -0,0 +1,116 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef MOVABLEOBJECT_H
#define MOVABLEOBJECT_H
#include "ButterflyEngine/components/basemotion.h"
#include <QQuaternion>
#include <QVector3D>
namespace ButterflyEngine {
class GuiObject;
/**
* @brief The MovableObject class contains functions for moving object on the world.
* All moving separate to next properties:
*
* * **Movable vector** This property sets direction of move
* * **Movable vector force** This is force of the movable vector.
* * **Angular velocity** This property sets spead of the angle moving.
* * **Braking force** This property are delta decriment the Power of the movable vector on time.
*/
class BUTTERFLY_ENGINE_EXPORT MovableObject: public BaseMotion
{
public:
MovableObject();
/**
* @brief render This impplementation of the render method add simulation of the physics in the vacuum space.
* @param tbfMsec This is time betwin frames argument.
*/
void render(unsigned int tbfMsec) override;
/**
* @brief movableVector This method return current mvable vector.
* The movable vector it is second point of line betwin object center and movableVector point.
* The movableVector base on own releative asix system wher the object center is vector {0 0 0}
* @note So movableVector are 3d angle of the moving of this object.
* @return movable vector of object
*/
const QVector3D &movableVector() const;
/**
* @brief setMovableVector This method sets new value of the mvable vector.
* @param newMovableVector this is a new value ofthe movable vector
* @note The movable vector will be changed in time if you set the MovableObject::breakingForce property to non 0 value.
*/
void setMovableVector(const QVector3D &newMovableVector);
/**
* @brief angularVelocity This method return current angular veloscity.
* @return angular velosity
* @note This property contains speed on angle per second (a/s)
*/
float angularVelocity() const;
/**
* @brief setAngularVelocity This method sets new value of the angular velacity in angele per second
* @param newAngularVelocity This is new value of the angular velacity
*/
void setAngularVelocity(float newAngularVelocity);
/**
* @brief breakingForce This method return current value of the breaking force.
* @return urrent value of the breaking force
*/
float breakingForce() const;
/**
* @brief setBreakingForce This method sets new value of the breaking force.
* @param newBreakingForce This is new value of the breaking force
*/
void setBreakingForce(float newBreakingForce);
/**
* @brief currentMovableVector This method return current movable vector.
* @return current movable vector.
*/
const QVector3D &currentMovableVector() const;
protected:
/**
* @brief renderRotation This method recalc raration for an @a object. The Default implementation converts movableVector to rotation of an @a object.
* @param object This is provessing object. Usually @a an object is casted pointer of this to GuiObject type.
* @param tbfMsec This is time betwin frames argument. soame as in the IRender::render function.
*/
void renderRotation(GuiObject* object, unsigned int tbfMsec) override;
/**
* @brief renderRotation This method recalc position for an @a object. The Default implementation move the current movable vector to setts movable vector. For example if you invoke the MovableObject::setMovableVector method then object change current movable vector with spead MovableObject::angularVelocity. If you sets
* @param object This is provessing object. Usually @a an object is casted pointer of this to GuiObject type.
* @param tbfMsec This is time betwin frames argument. soame as in the IRender::render function.
*/
void renderPosition(GuiObject* object, unsigned int tbfMsec) override;
private:
QVector3D _movableVector;
QVector3D _currentMovableVector;
QQuaternion _staticRotation = QQuaternion::fromEulerAngles(0,0,0);
float _angularVelocity = 0;
float _breakingForce = 0;
};
}
#endif // MOVABLEOBJECT_H

View File

@ -0,0 +1,28 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "rotationaroundaxis.h"
#include <ButterflyEngine/core/guiobject.h>
namespace ButterflyEngine {
RotationAroundAxis::RotationAroundAxis(): CircularMotion(nullptr) {
}
void RotationAroundAxis::renderRotation(GuiObject *object, unsigned int tbfMsec) {
setAnglePosition(anglePosition() + angularVelocity() * (tbfMsec / 1000.0f));
object->setRotation(QQuaternion::fromAxisAndAngle(axis(), angularVelocity()));
}
void RotationAroundAxis::renderPosition(GuiObject *, unsigned int ) {
}
}

View File

@ -0,0 +1,34 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef ROTATIONAROUNDAXIS_H
#define ROTATIONAROUNDAXIS_H
#include "circularmotion.h"
namespace ButterflyEngine {
/**
* @brief The RotationAroundAxis class This class provide the rotation of our axis
*/
class RotationAroundAxis: public CircularMotion
{
public:
RotationAroundAxis();
// BaseMotion interface
protected:
void renderRotation(GuiObject *object, unsigned int tbfMsec) override;
void renderPosition(GuiObject *object, unsigned int tbfMsec) override;
};
}
#endif // ROTATIONAROUNDAXIS_H

View File

@ -0,0 +1,32 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "affector.h"
namespace ButterflyEngine {
Affector::Affector(const QString &name,
const QString &viewTempalte,
QObject *ptr) :
IWorldItem(name, viewTempalte, ptr)
{
}
bool Affector::enabled() const {
return _enabled;
}
void Affector::setEnabled(bool newEnabled) {
if (_enabled == newEnabled)
return;
_enabled = newEnabled;
emit enabledChanged();
}
}

View File

@ -0,0 +1,79 @@
#ifndef AFFECTOR_H
#define AFFECTOR_H
#include "ButterflyEngine/interfaces/iworlditem.h"
namespace ButterflyEngine {
/**
* @brief The Affector class is an abstract base class of affectors like Gravity3D, Wander3D, and PointRotator3D. By default affectors affect all particles in the system,
* but this can be limited by defining the particles list.
* If the system has multiple affectors, the order of affectors may result in different outcome, as affectors are applied one after another.
*
* For custumisation your own Affectors you need to change the templateView qml file for your own class.
* @note For get more inforamtion about available qml affectors see the qt documentation [page](https://doc.qt.io/qt-6.1/qml-qtquick3d-particles3d-affector3d.html)
**Example of qml view file**
@code
Attractor3D {
property var model: null
property int guiId: (model) ? model.guiId : -1;
rotation: (model)? model.rotation: Qt.quaternion(0, 0, 0, 0)
scale: (model)? model.size: Qt.vector3d(0, 0, 0);
position: (model) ? model.position: Qt.vector3d(0,0,0);
visible: (model)? model.visible: false
enabled: (model)? model.enabled: false
positionVariation: Qt.vector3d(50, 50, 50)
duration: 3000
durationVariation: 1000
}
@endcode
*/
class BUTTERFLY_ENGINE_EXPORT Affector : public IWorldItem
{
Q_OBJECT
/**
* @brief enabled if enabled is set to false, this affector will not alter any particles. Usually this is used to conditionally turn an affector on or off.
The default value is true.
*/
Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
public:
Affector(const QString& name,
const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE,
QObject *ptr = nullptr);
/**
* @brief enabled if enabled is set to false, this affector will not alter any particles. Usually this is used to conditionally turn an affector on or off.
The default value is true.
* @return true if the Affector is enabled else false.
*/
bool enabled() const;
/**
* @brief setEnabled This method enable or disable the affector object.
* @param newEnabled new value.
*/
void setEnabled(bool newEnabled);
signals:
/**
* @brief enabledChanged This signal emited when the object change own enabled status.
*/
void enabledChanged();
private:
bool _enabled = true;
};
}
#endif // AFFECTOR_H

View File

@ -0,0 +1,43 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "ButterflyEngine/components/claster.h"
#include "clasteritem.h"
namespace ButterflyEngine {
ClasterItem::ClasterItem(const QString &name,
const QString &viewTempalte,
QObject *ptr):
IWorldItem(name, viewTempalte, ptr) {
}
ClasterItem::~ClasterItem() {
for (auto claster : qAsConst(_parentClasters)) {
claster->remove(this);
}
}
int ClasterItem::parentClastersCount() const {
return _parentClasters.size();
}
void ClasterItem::setClaster(Claster *claster) {
_parentClasters += claster;
}
void ClasterItem::removeClaster(Claster *claster) {
_parentClasters -= claster;
}
const QSet<Claster *> &ClasterItem::parentClasters() const {
return _parentClasters;
}
}

View File

@ -0,0 +1,66 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef CLASTERITEM_H
#define CLASTERITEM_H
#include "ButterflyEngine/interfaces/iworlditem.h"
#include <QSet>
namespace ButterflyEngine {
class Claster;
/**
* @brief The ClasterItem class This is item of the claster object. Thi class can be used as a one element of the claster class.
* @note This object invoke the Claster::remove method in destructor.
*/
class BUTTERFLY_ENGINE_EXPORT ClasterItem: public IWorldItem
{
Q_OBJECT
public:
ClasterItem(const QString& name,
const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE,
QObject *ptr = nullptr);
~ClasterItem();
/**
* @brief parentClastersCount This method return count of the parent clasters.
* @return parent clasters count
*/
int parentClastersCount() const;
protected:
/**
* @brief setClaster invoked when object added to new claster.
* @param claster pointer to invoker claster object.
*/
virtual void setClaster(Claster *claster);
/**
* @brief removeClaster
* @param claster
*/
virtual void removeClaster(Claster *claster);
/**
* @brief parentClasters return current parent clasters list;
* @return
*/
const QSet<Claster *> &parentClasters() const;
private:
QSet<Claster*> _parentClasters;
friend class Claster;
};
}
#endif // CLASTERITEM_H

View File

@ -0,0 +1,10 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "day.h"

View File

@ -0,0 +1,189 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef DAY_H
#define DAY_H
#include "dayitem.h"
#include "math.h"
#include <ButterflyEngine/components/claster.h>
namespace ButterflyEngine {
template <class Sun, class Moon>
/**
* @brief The Day class is template wrapper for the moon and sun objects.
* The moon and sun objects moving around world center for imitation of the day.
*
* ### Integration on the world.
* You need to add one object of this class in the IWorld::initWorldRules method.
* **Example:**
*
* ```cpp
* ButterflyEngine::WorldRule *World::initWorldRules() {
using Day = ButterflyEngine::Day<ButterflyEngine::Sun, ButterflyEngine::Moon>;
return new ButterflyEngine::WorldRule {
{0, {
{registerObject<Day>(), 1},
}
},
{1000, {
{registerObject<Day>(), 1},
}
},
};
}
* ```
* @note All objects will be moving around this objects with radius. The Radius by default is 1000.
* @note This class automaticly sets ligth force for the light objects.
*
*
*/
class Day: public IWorldItem, public Claster
{
public:
Day(): IWorldItem(AUTO_CLASS_NAME) {
static_assert(std::is_base_of_v<DayItem, Sun>,
"The Day class can be works only with DayItem child classes");
DayItem* sun = new Sun(&position());
DayItem* moon = new Moon(&position());
sun->setAnglePosition(0);
moon->setAnglePosition(180);
add(sun);
add(moon);
}
void render(unsigned int ) override {
setposition(getPlayer()->position() + QVector3D{0, 0, 0});
}
void add(ClasterItem *object) override {
if (auto item = dynamic_cast<DayItem*>(object)) {
item->setRadius(radius());
item->setAxis(_axis);
item->setAngularVelocity(lengthToSpeed(_dayLengthSec));
item->setLightForce(lengthForce());
Claster::add(item);
} else {
QuasarAppUtils::Params::log("The Day class can works only with "
" Child classes of the DayItem",
QuasarAppUtils::Error);
}
};
void remove(ClasterItem *object) override {
Claster::remove(object);
};
/**
* @brief radius This method return radius of the motion day objects.
* @return radius of the motions
*/
int radius() const {
return _radius;
}
/**
* @brief setRadius This method sets new value of the motions radius.
* @param newRadius This is new value o fthe motion.
*/
void setRadius(int newRadius) {
if (newRadius == _radius)
return;
_radius = newRadius;
for (auto object: objects()) {
reinterpret_cast<DayItem*>(object)->setLightForce(lengthForce());
reinterpret_cast<DayItem*>(object)->setRadius(_radius);
}
}
/**
* @brief axis This is sxis of rotation. all objects will be moving around this axis. The axis is general 3d vector object.
* @return rotation axis.
* @note By default it is y axis
*/
const QVector3D &axis() const {
return _axis;
}
/**
* @brief setAxis This method sets new value of the rotation axis. For get more information see the axis method.
* @param newAxis This is new value of the rotation axis.
*/
void setAxis(const QVector3D &newAxis) {
if (newAxis == _axis)
return;
_axis = newAxis;
for (auto object: objects()) {
reinterpret_cast<DayItem*>(object)->setAxis(_axis);
}
}
/**
* @brief dayLengthSec This method return length of the game day in real secs.
* @note by default this value is 360 sec
* @return length of the game day in real secs.
*/
float dayLengthSec() const {
return _dayLengthSec;
}
/**
* @brief setDayLengthSec This method sets new value of the day length.
* @param newDayLongSec This is new value of the day length.
* @note For get more information see the dayLengthSec method.
*/
void setDayLengthSec(float newDayLengthSec) {
if (newDayLengthSec == _dayLengthSec)
return;
_dayLengthSec = newDayLengthSec;
for (auto object: objects()) {
reinterpret_cast<DayItem*>(object)->setAngularVelocity(lengthToSpeed(_dayLengthSec));
}
}
private:
float lengthToSpeed(float length) const {
return (2 * M_PI * radius()) / length;
}
float lengthForce() const {
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
return _radius * 0.1;
#else
return _radius * 15;
#endif
}
int _radius = 1000;
float _dayLengthSec = 360;
QVector3D _axis = {1,0,0};
};
}
#endif // DAY_H

View File

@ -0,0 +1,29 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "dayitem.h"
namespace ButterflyEngine {
DayItem::DayItem(
const QVector3D* center,
const QString &name,
const QString &viewTempalte,
QObject *ptr):
IWorldLight(name, viewTempalte, ptr),
CircularMotion(center) {
}
void DayItem::render(unsigned int tbfMsec) {
CircularMotion::render(tbfMsec);
setVisible(position().z() > 0);
}
}

View File

@ -0,0 +1,29 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef DAYITEM_H
#define DAYITEM_H
#include "ButterflyEngine/interfaces/iworldlight.h"
#include "ButterflyEngine/components/circularmotion.h"
namespace ButterflyEngine {
/**
* @brief The DayItem class This is base class of the sun of moon of anther movable around center objects.
*/
class DayItem: public IWorldLight, public CircularMotion {
Q_OBJECT
public:
DayItem(const QVector3D* center,
const QString& name,
const QString& viewTempalte = "qrc:/CrawlModule/DayLight.qml",
QObject *ptr = nullptr);
void render(unsigned int tbfMsec);
};
}
#endif // DAYITEM_H

View File

@ -0,0 +1,19 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "defaultcontrol.h"
namespace ButterflyEngine {
DefaultControl::DefaultControl() {
}
QString DefaultControl::initQmlView() const {
return "qrc:/CrawlModule/DefaultMenu.qml";
}
}

View File

@ -0,0 +1,44 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef DEFAULTCONTROL_H
#define DEFAULTCONTROL_H
#include "player.h"
namespace ButterflyEngine {
/**
* @brief The DefaultControl class This class contains default implementation of the game menu.
*/
class BUTTERFLY_ENGINE_EXPORT DefaultControl : public Player {
Q_OBJECT
public:
DefaultControl();
/**
* @brief initQmlView This implementation use the DefaultMenu.qml file.
* @return qrc:/CrawlModule/DefaultMenu.qml
*/
QString initQmlView() const;
signals:
/**
* @brief backToMenu Emit when user click the return to main menu button.
*/
void backToMenu();
/**
* @brief userTap Emit when user tap to screen on any position.
*/
void userTap();
};
}
#endif // DEFAULTCONTROL_H

View File

@ -0,0 +1,27 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "defaultlight.h"
namespace ButterflyEngine {
DefaultLight::DefaultLight(): IWorldLight(AUTO_CLASS_NAME) {
setColor("#fff8e7");
setposition({10000, 0, 10000});
setRotation(QQuaternion::fromEulerAngles({-90,0,0}));
setLightForce(110);
}
void DefaultLight::render(unsigned int) {
}
void DefaultLight::init() {
}
}

View File

@ -0,0 +1,32 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef DEFAULTLIGHT_H
#define DEFAULTLIGHT_H
#include <ButterflyEngine/interfaces/iworldlight.h>
namespace ButterflyEngine {
/**
* @brief The DefaultLight class This is default implementation of the world light.
* This object create uniform illumination for all world.
* For integration This object yo worl see the IWorld::initWorldRules method
*/
class DefaultLight final: public IWorldLight
{
Q_OBJECT
public:
DefaultLight();
void render(unsigned int tbfMsec) override;
void init() override;
};
}
#endif // DEFAULTLIGHT_H

View File

@ -0,0 +1,21 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "diff.h"
namespace ButterflyEngine {
QList<int> Diff::getAddedIds() const {
return addedIds;
}
QList<int> Diff::getRemoveIds() const {
return removeIds;
}
}

View File

@ -0,0 +1,35 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef DIFF_H
#define DIFF_H
#include <QList>
#include <QObject>
namespace ButterflyEngine {
class GuiObject;
/**
* @brief The Diff class contains list of the last changes on a game world.
*/
class Diff {
Q_GADGET
public:
Q_INVOKABLE QList<int> getRemoveIds() const;
Q_INVOKABLE QList<int> getAddedIds() const;
QList<int> removeIds;
QList<int> addedIds;
};
}
Q_DECLARE_METATYPE(ButterflyEngine::Diff)
#endif // DIFF_H

View File

@ -0,0 +1,60 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "dynamicwint.h"
namespace ButterflyEngine {
DynamicWint::DynamicWint() {
}
void DynamicWint::render(unsigned int tbfMsec) {
_time += tbfMsec;
if (_time > _nextWintChange) {
setMagnitude(_baseMagnitude + (rand() % _magnitudeVariation) - _magnitudeVariation / 2 );
setDirection(QVector3D{static_cast<float>(rand()) - rand(), static_cast<float>(rand()) - rand(), static_cast<float>(rand()) - rand()} * _directionChangeMask);
_nextWintChange += ((rand() % 100) / 100.0f) * dayLengthSec() * 1000;
}
}
int DynamicWint::dayLengthSec() const {
return _dayLengthSec;
}
void DynamicWint::setDayLengthSec(int newDayLengthSec) {
_dayLengthSec = newDayLengthSec;
}
unsigned int DynamicWint::magnitudeVariation() const {
return _magnitudeVariation;
}
void DynamicWint::setMagnitudeVariation(unsigned int newMagnitudeVariation) {
_magnitudeVariation = newMagnitudeVariation;
}
unsigned int DynamicWint::baseMagnitude() const {
return _baseMagnitude;
}
void DynamicWint::setBaseMagnitude(unsigned int newBaseMagnitude) {
_baseMagnitude = newBaseMagnitude;
}
const QVector3D &DynamicWint::directionChangeMask() const {
return _directionChangeMask;
}
void DynamicWint::setDirectionChangeMask(const QVector3D &newDirectionChangeMask) {
_directionChangeMask = newDirectionChangeMask;
}
}

View File

@ -0,0 +1,90 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef DYNAMICWINT_H
#define DYNAMICWINT_H
#include "wint.h"
namespace ButterflyEngine {
/**
* @brief The DynamicWint class This implementation dynamicly change wint direction and magnituede per day.
*/
class BUTTERFLY_ENGINE_EXPORT DynamicWint : public Wint
{
Q_OBJECT
public:
DynamicWint();
// IRender interface
public:
void render(unsigned int tbfMsec) override;
/**
* @brief dayLengthSec This method return length of the game day in real secs.
* @note by default this value is 360 sec
* @return length of the game day in real secs.
*/
int dayLengthSec() const;
/**
* @brief setDayLengthSec This method sets new value of the day length.
* @param newDayLongSec This is new value of the day length.
* @note For get more information see the dayLengthSec method.
*/
void setDayLengthSec(int newDayLengthSec);
/**
* @brief magnitudeVariation This method return curerent value of the magnitude variation.
* @return curerent value of the magnitude variation.
*/
unsigned int magnitudeVariation() const;
/**
* @brief setMagnitudeVariation This method sets magnitude variation; by default it is 10
* @param newMagnitudeVariation This is new value of the magitude
*/
void setMagnitudeVariation(unsigned int newMagnitudeVariation);
/**
* @brief baseMagnitude This method return current base magnitude of the wint. The wint will be changed dynamicly one time per day length to the magnitudeVariation
* @return curretn value of the base magnitude
*/
unsigned int baseMagnitude() const;
/**
* @brief setBaseMagnitude This method sets new value of the base magnitude of the wint.
* @param newBaseMagnitude this is new value of the base magnitude of the wint.
*/
void setBaseMagnitude(unsigned int newBaseMagnitude);
/**
* @brief directionChangeMask This method return current value of mask of the direction variation. By default the wint will be changed by x and y axis.
* @return curertn value of the directionChangeMask
*/
const QVector3D &directionChangeMask() const;
/**
* @brief setDirectionChangeMask This method sets mask of the direction variation. By default the wint will be changed by x and y axis.
* @param newDirectionChangeMask This is new value of the directionChangeMask
*/
void setDirectionChangeMask(const QVector3D &newDirectionChangeMask);
private:
int _dayLengthSec = 360;
unsigned int _nextWintChange = 0;
unsigned int _time = 0;
unsigned int _magnitudeVariation = 50;
unsigned int _baseMagnitude = 50;
QVector3D _directionChangeMask = {1, 1, 0};
};
}
#endif // DYNAMICWINT_H

View File

@ -0,0 +1,49 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "fire.h"
namespace ButterflyEngine {
Fire::Fire(): ParticleEffect(AUTO_CLASS_NAME, "qrc:/CrawlModule/particles/Fire.qml") {
useDirectionVelosity({0, 0 , 10}, {10, 10, 0});
setParticleScale(1);
setParticleEndScale(3);
setParticleScaleVariation(3);
setLifeSpanVariation(500);
setColor("#ffaf2c");
setposition({0,0,1});
setEnabled(true);
setParticleDelegate("qrc:/CrawlModule/particles/FireParticel.qml");
setFireStrength(100);
}
void ButterflyEngine::Fire::onIntersects(const IWorldItem *) {
}
float Fire::fireStrength() const {
return _fireStrength;
}
void Fire::setFireStrength(float newFireStrength) {
if (qFuzzyCompare(_fireStrength, newFireStrength))
return;
_fireStrength = newFireStrength;
setEmitRate(10 + _fireStrength);
setLifeSpan(1000 + _fireStrength);
emit fireStrengthChanged();
}
}

View File

@ -0,0 +1,59 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef FIRE_H
#define FIRE_H
#include "particleeffect.h"
namespace ButterflyEngine {
/**
* @brief The Fire class This is default implementation of the Fire on game.
*/
class Fire: public ParticleEffect
{
Q_OBJECT
/**
* @brief fireStrength This propertye chenge fire power. By Default it is 100.
*/
Q_PROPERTY(float fireStrength READ fireStrength WRITE setFireStrength NOTIFY fireStrengthChanged)
public:
Fire();
// IWorldItem interface
/**
* @brief fireStrength This method return current value of the Fire::fireStrength propertye.
* @return current value of the Fire::fireStrength propertye.
*/
float fireStrength() const;
/**
* @brief setFireStrength This method sets new value of the Fire::fireStrength propertye.
* @param newFireStrength This is new value of the Fire::fireStrength prpertye.
* @warning This method change the emitRate, lifeSpan and velosity propertyes of this objects,
*/
void setFireStrength(float newFireStrength);
signals:
/**
* @brief fireStrengthChanged This signal emited when the Fire::fireStrength propertye is changed.
*/
void fireStrengthChanged();
protected:
void onIntersects(const IWorldItem *item);
private:
float _fireStrength = 0;
};
}
#endif // FIRE_H

View File

@ -0,0 +1,8 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "gameresult.h"

View File

@ -0,0 +1,31 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef GAMERESULT_H
#define GAMERESULT_H
namespace ButterflyEngine {
/**
* @brief The GameResult struct This is simple structure with game statistic.
*/
struct GameResult
{
/**
* @brief points This is count of the receved point in game.
*/
int points = 0;
/**
* @brief distance this is the distance traveled for the level.
*/
int distance = 0;
};
}
#endif // GAMERESULT_H

View File

@ -0,0 +1,12 @@
#ifndef Crawl_GLOBAL_H
#define Crawl_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(CRAWL_LIBRARY)
# define BUTTERFLY_ENGINE_EXPORT Q_DECL_EXPORT
#else
# define BUTTERFLY_ENGINE_EXPORT Q_DECL_IMPORT
#endif
#endif // QTSECRET_GLOBAL_H

View File

@ -0,0 +1,78 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "clasteritem.h"
#include "groundclaster.h"
namespace ButterflyEngine {
GroundClaster::GroundClaster(const QString &name,
const QString &viewTempalte,
QObject *ptr):
IWorldItem(name, viewTempalte, ptr) {
}
void GroundClaster::render(unsigned int ) {
const IWorldItem *playerObject = getPlayer();
if (!_itemsOrder.size()) {
QuasarAppUtils::Params::log("The GroundClaster do not have any claster items.",
QuasarAppUtils::Error);
return;
}
auto object = _itemsOrder.at(_index % _itemsOrder.size());
if (playerObject->position().distanceToPoint(object->position()) >
newObjectDistance()) {
auto prewObject = _itemsOrder.at((_index - 1) % _itemsOrder.size());
object->setposition({prewObject->position().x() + newObjectDistance(),
playerObject->position().y(),
object->position().z() - static_cast<float>(0.0001)});
_index++;
}
}
void GroundClaster::add(ClasterItem *object) {
object->setX(newObjectDistance() * _itemsOrder.count());
_itemsOrder.push_back(object);
Claster::add(object);
}
void GroundClaster::remove(ClasterItem *object) {
_itemsOrder.push_back(object);
Claster::remove(object);
}
void GroundClaster::remove(int id) {
_itemsOrder.push_back(objects().value(id));
Claster::remove(id);
}
void GroundClaster::init() {
generateItems();
}
int GroundClaster::newObjectDistance() const {
return 500;
}
unsigned int GroundClaster::itemsCount() const {
return 3;
}
}

View File

@ -0,0 +1,58 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef GROUNDCLASTER_H
#define GROUNDCLASTER_H
#include "ButterflyEngine/components/autogenerateclaster.h"
#include "global.h"
#include "ButterflyEngine/interfaces/iworlditem.h"
namespace ButterflyEngine {
/**
* @brief The GroundClaster class This is main control class for background plates of the world.
* Default behavior: create the tile grid and move old tiles to end of the world.
*
* @note use This class with child classes of the GroundTile class.
*/
class BUTTERFLY_ENGINE_EXPORT GroundClaster: public IWorldItem, public AutoGenerateClaster {
Q_OBJECT
public:
GroundClaster(const QString& name,
const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE,
QObject *ptr = nullptr);
// IRender interface
void render(unsigned int tbfMsec) override;
void add(ClasterItem *object) override;
void remove(ClasterItem *object) override;
void remove(int id) override;
void init() override;
unsigned int itemsCount() const override;
protected:
/**
* @brief newObjectDistance This method should be return default distance betwin clstersItems
* @return default distance betwin clstersItems
* @note By default this value equals 2000 points
*/
virtual int newObjectDistance() const;
private:
QList<ClasterItem*> _itemsOrder;
unsigned int _index = 0;
};
}
#endif // GROUNDCLASTER_H

View File

@ -0,0 +1,14 @@
#include "groundtile.h"
namespace ButterflyEngine {
GroundTile::GroundTile(const QString &name,
const QString &viewTempalte,
QObject *ptr):
ClasterItem(name, viewTempalte, ptr) {
}
void ButterflyEngine::GroundTile::render(unsigned int) {
}
}

View File

@ -0,0 +1,38 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef GROUNDTILE_H
#define GROUNDTILE_H
#include "clasteritem.h"
namespace ButterflyEngine {
/**
* @brief The GroundTile class It reimplementation of the ClasterItem. The groundTile do not heve own render function because the GroundClaster class control position of this class.
*
* @note use This class with the GroundClaster class.
*/
class BUTTERFLY_ENGINE_EXPORT GroundTile: public ClasterItem
{
Q_OBJECT
public:
GroundTile(const QString& name,
const QString& viewTempalte = DEFAULT_VIEW_TEMPLATE,
QObject *ptr = nullptr);
// IRender interface
public:
/**
* @brief render The current render implementation do nothing.
* @param tbfMsec This is time betwin frames value. (in milleseconds)
*/
void render(unsigned int tbfMsec) override;
};
}
#endif // GROUNDTILE_H

View File

@ -0,0 +1,104 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#include "clasteritem.h"
#include "groupobject.h"
namespace ButterflyEngine {
GroupObject::GroupObject() {
}
void GroupObject::render(unsigned int tbfMsec) {
Q_UNUSED(tbfMsec)
GuiObject* _this = checkminimumRequariedType<GuiObject>();
for (ClasterItem* object: objects()) {
if (Localpropertys *props = getLocalpropertys(object->guiId())) {
if (!props->_rotation.isNull())
object->setRotation(_this->rotation() * props->_rotation);
QVector3D reCalcVectorPs = reCalcPos(props->_position,
_this->rotation().toEulerAngles());
object->setposition(_this->position() + reCalcVectorPs);
}
}
}
void GroupObject::installObject(ClasterItem *object,
const QVector3D &localPosition,
const QQuaternion &localRotation) {
updatePosition(object->guiId(), localPosition);
updateRotation(object->guiId(), localRotation);
Claster::add(object);
}
void GroupObject::updatePosition(int id, const QVector3D &position) {
_extrapropertys[id]._position = position;
}
void GroupObject::updateRotation(int id, const QQuaternion &roatation) {
_extrapropertys[id]._rotation = roatation;
}
const QVector3D GroupObject::reCalcPos(const QVector3D& pos, const QVector3D &eulerAngles) const
{
float alha = eulerAngles.z();
float beta = eulerAngles.y();
float gamma = eulerAngles.x();
float x = pos.x();
float y = pos.y();
float z = pos.z();
float newX = x*(qCos(alha)*qCos(beta)) +
y*(qCos(alha)*qSin(beta)*qSin(gamma) - qSin(alha)*qCos(gamma)) +
z*(qCos(alha)*qSin(beta)*qCos(gamma) + qSin(alha)*qSin(gamma));
float newY = x*(qSin(alha)*qCos(beta)) +
y*(qSin(alha)*qSin(beta)*qSin(gamma) + qCos(alha)*qCos(gamma)) +
z*(qSin(alha)*qSin(beta)*qCos(gamma) - qCos(alha)*qSin(gamma));
float newZ = x*(-qSin(beta)) +
y*(qCos(beta)*qSin(gamma)) +
z*(qCos(beta)*qCos(gamma));
return QVector3D({newX, newY, newZ});
}
QQuaternion *GroupObject::getLocalrotation(int id) {
if (_extrapropertys.contains(id)) {
return &_extrapropertys[id]._rotation;
}
return nullptr;
}
QVector3D *GroupObject::getLocalPosition(int id) {
if (_extrapropertys.contains(id)) {
return &_extrapropertys[id]._position;
}
return nullptr;
}
Localpropertys *GroupObject::getLocalpropertys(int id) {
if (_extrapropertys.contains(id)) {
return &_extrapropertys[id];
}
return nullptr;
}
}

View File

@ -0,0 +1,134 @@
//#
//# Copyright (C) 2021-2024 QuasarApp.
//# Distributed under the GPLv3 software license, see the accompanying
//# Everyone is permitted to copy and distribute verbatim copies
//# of this license document, but changing it is not allowed.
//#
#ifndef GROUPOBJECT_H
#define GROUPOBJECT_H
#include <ButterflyEngine/interfaces/irender.h>
#include <ButterflyEngine/components/claster.h>
#include <QQuaternion>
#include <QVector3D>
namespace ButterflyEngine {
/**
* @brief The Localpropertys struct This structure contains local propertys of the all childs object of a GroupObject class object.
*/
struct Localpropertys {
QVector3D _position = {0,0,0};
QQuaternion _rotation = {};
};
/**
* @brief The GroupObject class is extension with group object behavior.
* ### Requried child classes: IWorldItem
*
* This class have implementation of the render method that move all child objects on selected local positions on parent object.
*
* ## Example of use
*
* ### For what this object uses
*This object will be very convenient where you want to create a directly cluster object with multiple sub objects that should contains in the parent root object.
* For example : weapon of the player.
*
* ### Example of use
*
* 1. create the Player class:
*
* ```cpp
* const QVector3d weaponPosition = {1,0,0};
* const QQuaternion weaponRotation = QQuaternion::fromEilorAngle(90,0,0);
*
* class Player: public IWorldItem, public GroupObject {
* //... some implementation
* void setWeapon(WeaponObject * weapon) {
* installObject(weapon, weaponPosition, weaponRotation);
* }
* //... some implementation
* };
* ```
*
* All done. Now the weapon will be static on forward of the Player object.
*
* You can change the position and rotation of the weapon object using updatePosition and updateRotation methods.
*
* @note This class requried the GuiObject functions as a parent class.
*/
class GroupObject: public IRender, public Claster
{
public:
GroupObject();
void render(unsigned int tbfMsec);
/**
* @brief installObject This method is wrapper of the Claster::add method
* but sets local position and local rotation for an @a object releative current object.
* @param object This is pointer to the adding object.
* @param localPosition This is local position of the @a object. The default value is current object center.
* @param localRotation This is local rotation of the @a object. The default value is invalid quaternion and will be ignored..
* @note The @a object should be disable own render method of a render method
* or @a object should not be change position and rotation propertys
* @note if you want to ignore the local rotation functionality then set the @a localRotation argument to invalid or default value.
*/
void installObject(ClasterItem* object,
const QVector3D& localPosition = {0,0,0},
const QQuaternion& localRotation = {});
/**
* @brief updatePosition This method sets new releative position of the child object.
* @param id This is id of the object that position need to change.
* @param position This is new value of the object position
*/
void updatePosition(int id, const QVector3D& position);
/**
* @brief updateRotation This method sets new raleative rotation of the object with @a id.
* @param id This is id of the object that rotation need to change
* @param roatation This is new value of the object with @a id.
*/
void updateRotation(int id, const QQuaternion& roatation);
protected:
/**
* @brief getLocalrotation This method return current local rotation of the object with @a id.
* @param id This is id of the object that rotation will be returned.
* @return current local rotation ot the object winth @a id. IF the object with id not exists on this classter then return nullptr.
* @warning use this return not const pointer and you can change them value without invoke the updatePosition method but this is not thread safe.
*/
QQuaternion* getLocalrotation(int id);
/**
* @brief getLocalPosition This method return current local position of the object with @a id.
* @param id This is id of the object that position will be returned.
* @return current local position ot the object winth @a id. IF the object with id not exists on this classter then return nullptr.
* @warning use this return not const pointer and you can change them value without invoke the updateRotation method but this is not thread safe.
*/
QVector3D* getLocalPosition(int id);
/**
* @brief getLocalpropertys This method return all local propertys of an object with @a id
* @param id This is id of the object for getting changes.
* @return pointer to structure with local propertys of the object. IF the object with id not exists on this classter then return nullptr.
* @warning use this return not const pointer and you can change them value but this is not thread safe.
*/
Localpropertys* getLocalpropertys(int id);
private:
QHash<int, Localpropertys> _extrapropertys;
const QVector3D reCalcPos(const QVector3D& pos, const QVector3D& eulerAngles) const;
};
}
#endif // GROUPOBJECT_H

Some files were not shown because too many files have changed in this diff Show More