diff --git a/.luarc.json b/.luarc.json index 07d83c5..e54d37a 100644 --- a/.luarc.json +++ b/.luarc.json @@ -28,7 +28,7 @@ ], "runtime.version": "Lua 5.4", "workspace.library": [ - "/home/ut3usw/src/playdate-luacats", - "/home/ut3usw/Projects/VSCode-PlaydateTemplate/source/libraries" + "/Users/oleksiiilienko/projects/playdate-luacats", + "/Users/oleksiiilienko/Documents/fpv2/source/libraries" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..0e19324 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "playdate", + "request": "launch", + "name": "Playdate: Debug", + "preLaunchTask": "${defaultBuildTask}" + } + ] + } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index b47c477..526d129 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,4 +5,8 @@ "Lua.runtime.nonstandardSymbol": ["+=", "-=", "*=", "/=", "//=", "%=", "<<=", ">>=", "&=", "|=", "^="], "Lua.workspace.library": ["$PLAYDATE_SDK_PATH/CoreLibs"], "Lua.workspace.preloadFileSize": 1000, -} + "playdate-debug.sdkPath": "/Users/oleksiiilienko/Developer/PlaydateSDK", + "playdate-debug.sourcePath": "/Users/oleksiiilienko/Documents/fpv2/source", + "playdate-debug.outputPath": "/Users/oleksiiilienko/Documents/fpv2/builds", + "playdate-debug.productName": "FPV Game" +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 6399696..762ab3f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -3,6 +3,26 @@ // for the documentation about the tasks.json format "version": "2.0.0", "tasks": [ + { + "type": "pdc", + "problemMatcher": ["$pdc-lua", "$pdc-external"], + "label": "Playdate: Build" + }, + { + "type": "playdate-simulator", + "problemMatcher": ["$pdc-external"], + "label": "Playdate: Run" + }, + { + "label": "Playdate: Build and Run", + "dependsOn": ["Playdate: Build", "Playdate: Run"], + "dependsOrder": "sequence", + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + } + }, { "label": "Invoke Build and Run script", "type": "shell", @@ -29,6 +49,12 @@ "build" ] }, + "osx": { + "command": "${workspaceFolder}/build_and_run_mac.sh", + "args": [ + "build" + ] + }, "presentation": { "showReuseMessage": false, "reveal": "always", @@ -62,6 +88,12 @@ "run" ] }, + "osx": { + "command": "${workspaceFolder}/build_and_run_mac.sh", + "args": [ + "run" + ] + }, "presentation": { "showReuseMessage": false, "reveal": "always", diff --git a/build_and_run_mac.sh b/build_and_run_mac.sh new file mode 100755 index 0000000..304e721 --- /dev/null +++ b/build_and_run_mac.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash + +export PLAYDATE_SDK_PATH="/Users/oleksiiilienko/Developer/PlaydateSDK" + +# Check for color by variable and tput command +if [[ -z $NOCOLOR && -n $(command -v tput) ]]; then + RED=$(tput setaf 1) + CYN=$(tput setaf 6) + YEL=$(tput setaf 3) + RST=$(tput sgr0) +fi + +function display_help() { + printf "%s\n\n" "${0} build|run|-h|--help|" + printf "%-16s\n" "build: Builds the project and runs the Simulator" + printf "%-16s\n" "run : Skips building the project and runs the Simulator" + printf "\n" + printf "%s\n\n" "Set NOCOLOR=1 to disable terminal coloring" + exit 0 +} + +# We don't need fancy flags/operators for two commands +case $1 in + "build") + BUILD=1 + ;; + "run") + BUILD=0 + ;; + *) + display_help + exit 1 + ;; +esac + +# Set some paths +BUILD_DIR="./builds" +SOURCE_DIR="./source" +PDX_PATH="${BUILD_DIR}/$(basename $(pwd)).pdx" + +# Logging functions +function log() { + printf "%s\n" "${CYN}>> $1${RST}" +} +function log_warn() { + printf "%s\n" "${YEL}>! $1${RST}" +} +function log_err() { + printf "%s\n >> %s\n" "${RED}!! ERROR !!" "$1${RST}" +} + +function check_pdxinfo() { + if [[ -f ./source/pdxinfo ]]; then + if grep "com.organization.package" ./source/pdxinfo 2>&1 >/dev/null; then + log_warn "PDXINFO NOTICE:" + log_warn "Don't forget to change your unique project info in 'source/pdxinfo': 'bundleID', 'name', 'author', 'description'." + log_warn "It's critical to change your game bundleID, so there will be no collisions with other games, installed via sideload." + log_warn "Read more about pdxinfo here: https://sdk.play.date/Inside%20Playdate.html#pdxinfo" + fi + fi +} + +function chk_err() { + # Check for errors in last process and bail if needed + if [[ $? > 0 ]]; then + log_err "There was an issue with the previous command; exiting!" + exit 1 + fi +} + +function check_close_sim() { + # Check if we have 'pidof' + PIDOF=$(command -v pidof2) + + # Prefer 'pidof'; use ps if not + if [[ -n $PIDOF ]]; then + SIMPID=$($PIDOF "PlaydateSimulator") + if [[ -n $SIMPID ]]; then + log "Found existing Simulator, closing..." + kill -9 $SIMPID + chk_err + fi + else + SIMPID=$(ps aux | grep PlaydateSimulator | grep -v grep | awk '{print $2}') + if [[ -n $SIMPID ]]; then + log "Found existing Simulator, closing..." + kill -9 $SIMPID + chk_err + fi + fi +} + +# Create build dir +function make_build_dir() { + if [[ ! -d "${BUILD_DIR}" ]]; then + log "Creating build directory..." + mkdir -p "${BUILD_DIR}" + chk_err + fi +} + +# Clean build dir +function clean_build_dir() { + if [[ -d "${BUILD_DIR}" ]]; then + log "Cleaning build directory..." + rm -rfv "${BUILD_DIR}/*" + chk_err + fi +} + +# Compile the PDX +function build_pdx() { + if [[ $BUILD == 1 ]]; then + log "Building PDX with 'pdc'..." + $PLAYDATE_SDK_PATH/bin/pdc -sdkpath "${PLAYDATE_SDK_PATH}" "${SOURCE_DIR}" "${PDX_PATH}" + chk_err + fi +} + +# Run the PDX with Simulator +function run_pdx() { + if [[ -d "${PDX_PATH}" ]]; then + log "Running PDX with Simulator..." + open -a "$PLAYDATE_SDK_PATH/bin/Playdate Simulator.app" "${PDX_PATH}" + else + log_err "PDX doesn't exist! Please 'build' the project first!" + fi +} + + +#### MAIN SCRIPT #### +if [[ $BUILD == 1 ]]; then + log "Attempting a build and run of PDX..." + make_build_dir + clean_build_dir + check_pdxinfo + build_pdx + check_close_sim + run_pdx +else + log "Attempting to run PDX: ${PDX_PATH}..." + check_close_sim + run_pdx +fi + diff --git a/source/assets/audio/back.wav b/source/assets/audio/back.wav new file mode 100644 index 0000000..aff8b31 Binary files /dev/null and b/source/assets/audio/back.wav differ diff --git a/source/assets/fonts/Outfoxies.fnt b/source/assets/fonts/Outfoxies.fnt new file mode 100644 index 0000000..a78f131 --- /dev/null +++ b/source/assets/fonts/Outfoxies.fnt @@ -0,0 +1,47 @@ +--metrics={"baseline":7,"xHeight":0,"capHeight":0,"pairs":{},"left":[],"right":[]} +datalen=1204 +data=iVBORw0KGgoAAAANSUhEUgAAADgAAAAwCAYAAABE1blzAAAAAXNSR0IArs4c6QAAA0BJREFUaEPdWdtyqzAQa/7/o9uBqVMhpNUaCE17njr22uxVknMeHz//PuHv8eeD1tAG99TZ5eiwSfvjM2w3c176zxcop5XNchnbumQs62y/BDQccj7gGXc++f9Ag+EIZ55thnOpghiY647hOAaLa84/7jC+57mvLmDHuhXExLgKuQ5xgY47UwfYfVcddTFnWVW6qhSPuEsk2rnKsH/Kbr0/9bBrV25TlUG06VQAA+Nx6Z7fdUhnjhzCdVASMy1AegNU6juXoaj6+L9YSxlKVZrpgG7CqnZXc4yAtttXIFMNeYWCCUU7ASYhkVCYfd8oDRzsNkp9E75FMRIEVZCVeEj3t1EUCbSiBeY5ViUIGKxwVJCO6CsebKG0kldKWqUMqjlwEo0DTNzpFJHiUW7xJw9yxlW7pBnrnHEtunMMDF0gSSisd6oKYpvuhpY8vBJFXSW5OxxWSJ7tzEcH/a6yUUL71N3dCqjsJo5UgCWz/L1YfSO1sMKA1b+uFu1oQdUNqSIMXgn0+D70S9IME73KlBK+HZ7kCvLsnN1nlJa0pgJUQ8yc4wJkUKqUkso+82m3AywL/HYFZ75fKS2cwU3H3T2DSUi/bAYtCjUQzp11KOqo6aUoeopr3vlwJ5sO/RwPOrqoKnqY51KHVQFWYlZBNK8pRK1oqAIR9VpRL5CdtDwSIPMiU0hF+GjrzrmnU0qA3GcUrQg8IW63gq4zrli3FUzvPSWReAbVrB7lua4AcX495z1VRVWU17jtWFWoVnSasiMV8f6oqHBeuu8xbAPV4mnfzVLiza5/GwxwIPPO1Dbl21UVrNRMxaPYYmd40vLo7AzuUAp+NkTQ4TmsNOgV6Gln+ijKVXTCLdSduW6gXGk+t9mv4Fh9cKaCTn0ovqxQlYWF+hVguoLpUkcfjKDyZwTxX9qJhyuqcepoXXcz2MnoTIXTTCatiSDGyefgZYvOoGCaKcWDTM4OkNT8qrHg8xFFp7jlLxlXYvsoL6Uq3Jqfq2mCnXf8d1uQCmQcDDvkdK8IBRy3BYbtxwCgUCqhWGf/9uAQidwrWqGVI2qscIWktwbancEOj6mXydvNoKqCe3Gkl4gag1urp8j2dgde/cEvnycmPQiDA1YAAAAASUVORK5CYII= +width=8 +height=8 + +tracking=1 + +0 8 +1 8 +2 8 +3 8 +4 8 +5 8 +6 8 +7 8 +8 8 +9 8 +space 8 +� 8 +A 8 +B 8 +C 8 +D 8 +E 8 +F 8 +G 8 +H 8 +I 8 +J 8 +K 8 +L 8 +M 8 +N 8 +O 8 +P 8 +Q 8 +R 8 +S 8 +T 8 +U 8 +V 8 +W 8 +X 8 +Y 8 +Z 8 + diff --git a/source/assets/images/maps/map_1.png b/source/assets/images/maps/map_1.png new file mode 100644 index 0000000..8080024 Binary files /dev/null and b/source/assets/images/maps/map_1.png differ diff --git a/source/main.lua b/source/main.lua index 871bb8e..f71332f 100644 --- a/source/main.lua +++ b/source/main.lua @@ -34,6 +34,15 @@ CollideGroups = { wall = 5 } +Maps = { + { + id = 1, + name = "Vovchansk", + description = "This is a map", + locked = false, + } +} + Drones = { { id = 1, @@ -84,12 +93,14 @@ import "scripts/progressBar" import "scripts/selectionSprite" import "scripts/DroneCard" import "scripts/pageSprite" +import "scripts/MapCard" import "scenes/BaseScene" import 'scenes/Assemble' import 'scenes/DroneCardSelector' import 'scenes/Menu' import 'scenes/Game' +import 'scenes/MapSelector' Difficulty = { Easy = "Easy", diff --git a/source/scenes/Assemble.lua b/source/scenes/Assemble.lua index 43ef422..e9c593a 100644 --- a/source/scenes/Assemble.lua +++ b/source/scenes/Assemble.lua @@ -132,21 +132,24 @@ end function scene:start() scene.super.start(self) + self.optionsMenu:addMenuItem("Main Menu", function() Noble.transition(Menu) end) Noble.showFPS = false + if scene.musicEnabled then + scene.levelAudio:play(0) + end end function scene:enter() scene.super.enter(self) - + local soundTable = playdate.sound.playingSources() + for i=1, #soundTable do + soundTable[i]:stop() + end scene.buttonTimeout = 100 Noble.Input.setHandler(scene.inputHandler) - - if scene.musicEnabled then - scene.levelAudio:play(0) - end local text = [[The drone is assembled and operational. We are ready for the mission. @@ -226,6 +229,10 @@ function scene:update() self.tickTimer:remove() screenShake(100, 5) Noble.Input.setEnabled(false) + playdate.timer.performAfterDelay(2500, function() -- Return to the start after failure + Noble.Input.setEnabled(true) + Noble.transition(DroneCardSelector, nil, Noble.Transition.SpotlightMask); + end) return end diff --git a/source/scenes/DroneCardSelector.lua b/source/scenes/DroneCardSelector.lua index 2b37938..658131e 100644 --- a/source/scenes/DroneCardSelector.lua +++ b/source/scenes/DroneCardSelector.lua @@ -12,7 +12,10 @@ scene.inputHandler = { scene.menuConfirmSound:play(1) Noble.transition(Assemble) end, - BButtonDown = function() end, + BButtonDown = function() + scene.menuBackSound:play(1) + Noble.transition(MapSelector) + end, downButtonDown = function() end, leftButtonDown = function() @@ -41,7 +44,9 @@ function scene:setValues() self.menuIndex = 1 self.aKey = Graphics.image.new("assets/sprites/buttons/A") + self.bKey = Graphics.image.new("assets/sprites/buttons/B") scene.menuConfirmSound = playdate.sound.fileplayer.new("assets/audio/confirm") + scene.menuBackSound = playdate.sound.fileplayer.new("assets/audio/back") scene.menuSelSound = playdate.sound.fileplayer.new("assets/audio/menu_select") scene.menuSelSound:setVolume(0.5) @@ -64,12 +69,10 @@ end function scene:enter() scene.super.enter(self) - scene.cards = { - DroneCard(0, 0, Drones[1]), - DroneCard(0, 0, Drones[2]), - DroneCard(0, 0, Drones[3]), - DroneCard(0, 0, Drones[4]), - } + scene.cards = {} + for i = 1, #Drones do + scene.cards[i] = DroneCard(0, 0, Drones[i]) + end scene.paginator = PageSprite(200, 207) end @@ -91,7 +94,7 @@ function scene:update() end local x = 0 - for i = 1, 4 do + for i = 1, #scene.cards do x = 29 + (339 + 16) * (i - 1) scene.cards[i]:moveTo(x + scene.currentX, 25) end @@ -101,12 +104,15 @@ function scene:update() Noble.Text.draw("Assemble", 333, 210, Noble.Text.ALIGN_LEFT, false, fontMed) end + self.bKey:draw(15, 207 + dy) + Noble.Text.draw("Back", 33, 210, Noble.Text.ALIGN_LEFT, false, fontMed) + scene.paginator:moveTo(200, 207) end function scene:exit() scene.super.exit(self) - for i = 1, 4 do + for i = 1, #scene.cards do scene.cards[i]:remove() end Noble.showFPS = false diff --git a/source/scenes/MapSelector.lua b/source/scenes/MapSelector.lua new file mode 100644 index 0000000..0fa0cb1 --- /dev/null +++ b/source/scenes/MapSelector.lua @@ -0,0 +1,123 @@ +MapSelector = {} +class("MapSelector").extends(BaseScene) +local scene = MapSelector +local fontMed = Graphics.font.new('assets/fonts/onyx_9') +local fontBig = Graphics.font.new('assets/fonts/opal_12') +local elapsedTime = 0 + +function scene:init() + playdate.graphics.setImageDrawMode(playdate.graphics.kDrawModeXOR) + scene.super.init(self) + scene.menuIndex = 1 + + self.aKey = Graphics.image.new("assets/sprites/buttons/A") + self.bKey = Graphics.image.new("assets/sprites/buttons/B") + + scene.menuConfirmSound = playdate.sound.fileplayer.new("assets/audio/confirm") + scene.menuBackSound = playdate.sound.fileplayer.new("assets/audio/back") + + scene.menuSelSound = playdate.sound.fileplayer.new("assets/audio/menu_select") + scene.menuSelSound:setVolume(0.5) + + scene.currentX = 0 + scene.targetX = 0 +end + +function scene:start() + scene.super.start(self) + + Noble.showFPS = false + + self.optionsMenu:addMenuItem("Main Menu", function() Noble.transition(Menu) end) +end + + +function scene:enter() + scene.super.enter(self) + scene.cards = {} + for i = 1, #Maps do + scene.cards[i] = MapCard(0, 0, Maps[i]) + end +end + +function scene:update() + scene.super.update(self) + elapsedTime = elapsedTime + 1 / playdate.display.getRefreshRate() + + local dy = 2 * math.sin(20 * elapsedTime) + + local speed = 40 + if math.abs(scene.targetX - scene.currentX) < speed then + scene.currentX = scene.targetX + else + scene.currentX = scene.currentX + speed * ((scene.targetX > scene.currentX) and 1 or -1) + end + + local x = 0 + for i = 1, #scene.cards do + x = 0 + (339 + 16) * (i - 1) + scene.cards[i]:moveTo(x + scene.currentX, 0) + end + + -- Bottom background + if Maps[scene.menuIndex].locked == false then + self.aKey:draw(315, 207 + dy) + Noble.Text.draw("Select", 333, 210, Noble.Text.ALIGN_LEFT, false, fontMed) + end + + self.bKey:draw(15, 207 + dy) + Noble.Text.draw("Back", 33, 210, Noble.Text.ALIGN_LEFT, false, fontMed) + + Noble.Text.draw(string.upper(Maps[scene.menuIndex].name), 200, 210, Noble.Text.ALIGN_CENTER, false, fontBig) + + +end + +function scene:exit() + scene.super.exit(self) + for i = 1, #scene.cards do + scene.cards[i]:remove() + end + Noble.showFPS = false + playdate.graphics.setImageDrawMode(playdate.graphics.kDrawModeXOR) +end + +function scene:finish() + scene.super.finish(self) + for i = 1, #scene.cards do + scene.cards[i]:remove() + end + playdate.display.setScale(1) +end + +scene.inputHandler = { + AButtonDown = function() + if Maps[scene.menuIndex].locked then + return + end + scene.menuConfirmSound:play(1) + Noble.transition(DroneCardSelector) + end, + BButtonDown = function() + scene.menuBackSound:play(1) + Noble.transition(Menu) + end, + leftButtonDown = function() + if scene.menuIndex <= 1 then + return + end + scene.menuSelSound:play(1) + scene.targetX = scene.targetX + 355 + scene.menuIndex = scene.menuIndex - 1 + end, + rightButtonDown = function() + if scene.menuIndex >= #Maps then + return + end + scene.menuSelSound:play(1) + scene.targetX = scene.targetX - 355 + scene.menuIndex = scene.menuIndex + 1 + end, + upButtonDown = function() + end, +} \ No newline at end of file diff --git a/source/scenes/Menu.lua b/source/scenes/Menu.lua index d99b8ee..c213420 100644 --- a/source/scenes/Menu.lua +++ b/source/scenes/Menu.lua @@ -106,13 +106,13 @@ end function scene:exit() scene.super.exit(self) - scene.levelAudio:stop() + -- scene.levelAudio:stop() self.sequence = Sequence.new():from(self.menuY):to(self.menuYTo, 0.5, Ease.inSine) self.sequence:start() end function scene:setupMenu(__menu) - __menu:addItem("Start", function() Noble.transition(DroneCardSelector, nil, Noble.Transition.DipToWhite) end) + __menu:addItem("Start", function() Noble.transition(MapSelector, nil, Noble.Transition.DipToWhite) end) __menu:addItem("Tutorial", function() local debug = Noble.Settings.get("debug") if debug then diff --git a/source/scripts/MapCard.lua b/source/scripts/MapCard.lua new file mode 100644 index 0000000..d69f4f7 --- /dev/null +++ b/source/scripts/MapCard.lua @@ -0,0 +1,11 @@ +local pd = playdate +local gfx = Graphics + +class('MapCard').extends(gfx.sprite) + +function MapCard:init(x, y, map) + self:setImage(gfx.image.new('assets/images/maps/map_' .. map.id .. '.png')) + self:setCenter(0, 0) + self:moveTo(x, y) + self:add() +end