Code Monkey home page Code Monkey logo

playdatekit's Introduction

PlaydateKit Logo

PlaydateKit

PlaydateKit provides easy to use Swift bindings for the Playdate C API. PlaydateKit aims to be as Swift-y as possible, replacing error pointers with throwable functions, avoiding the use of pointers and memory management as much as possible, and adding documentation comments to all functions (copied from the Playdate SDK docs).

Status

PlaydateKit provides (almost) full coverage of the Playdate C API. PlaydateKit adds wrapper types for some values (Sprite, Bitmap, FileHandle, etc) that automatically manage the allocation/deallocation of resources. While I have attempted to closely follow the C API specifications, much of it is untested, so if you run into an unexpected issue or can't do something with the Swift API, please open an issue!

Currently, the following sections of the API are implemented:

  • Display
  • File
  • Graphics
  • JSON
  • Lua
  • Scoreboards
  • Sound
    • FilePlayer
    • SamplePlayer
    • Synth (partial)
  • Sprite
  • System

Usage

For detailed instructions and documentation on how to get started creating a game using PlaydateKit, see here.

Summary

  1. Install a recent nightly Swift toolchain that supports the Embedded experimental feature.
  2. Install the Playdate SDK.
  3. Create a new repository using the PlaydateKitTemplate template.
  4. Build and run directly in the simulator using Xcode, or build using the command swift package pdc. When built using swift package pdc, the built pdx game file will be located at .build/plugins/PDCPlugin/outputs/PlaydateKitTemplate.pdx and can be opened in the Playdate simulator.

Your PlaydateGame object manages the game lifecycle, receiving events such as gameWillPause and deviceWillSleep.

import PlaydateKit

final class Game: PlaydateGame {
    init() {
        System.addCheckmarkMenuItem(title: "check me") { isChecked in
            print(isChecked ? "checked!" : "not checked")
        }
    }

    func update() -> Bool {
        System.drawFPS()
        return true
    }

    func gameWillPause() {
        print("Paused!")
    }
}

Contributing

I'm happy to accept contributions on this project, whether it's bug fixes, implementing missing features, or opening an issue. Please try to follow the existing conventions/style in the project.

If you create a game using PlaydateKit and would like it featured here, please open an issue or pull request! If you would like to demake a retro game or create a new one that demonstrates PlaydateKit's capabilities, feel free to add an example game in the Examples/ directory.

Acknowledgements

PlaydateKit was inspired by and would not be possible without the excellent work done by @rauhul on swift-playdate-examples. Specifically, PlaydateKit was created due to the note in the swift-playdate-examples repo:

It is not intended to be a full-featured Playdate SDK so please do not raise PRs to extend the Playdate Swift overlay to new areas.

playdatekit's People

Contributors

aechaves avatar alicerunsonfedora avatar eugeniobaglieri avatar finnvoor avatar pcbeard avatar ricobeck avatar tyetrask avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

playdatekit's Issues

Move drawFunction and updateFunction to methods on Sprite class

Callbacks that give the sprite pointer aren't really usable, it would be better to make them methods on the Sprite class that you can override. Will need to keep a (weak?) reference to the sprite somewhere globally to call the right update method.

requires making sprite open (#11)

(String) Unicode Data Table Support via PDCPlugin?

With String landing in Embedded Swift, it's been really nice working in PlaydateKit but I still find myself wanting more, if not the full, String API 😅 (comparison, iteration, string keys in dictionaries, etc.).

I'm curious if you're interested and/or were planning to add this as an option to the PDC plugin so that users could choose whether to opt into linking the data tables?

I've been experimenting with how to link the unicode data tables to get this but I'm not having much luck so far (I have very little experience with compilation/linking so I apologize in advance if what I've tried isn't making much sense).

(I've posted about it in the Playdate Squad discord here in case any onlookers might be able to assist as well.)

After looking at the Swift Embedded user manual, I understood the gist and set out to modify PDCPlugin's clang and cc command flags.

let triple = "armv7em-none-none-eabi"
let toolchainPath = "\(home)Library/Developer/Toolchains/swift-latest.xctoolchain"
let unicodeDataTablesPathDevice = "\(toolchainPath)/usr/lib/swift/embedded/\(triple)"
let unicodeDataTablesPathSimulator = "\(toolchainPath)/usr/lib/swift/embedded/arm64-apple-none-macho"
let unicodeDataTablesLibName = "swiftUnicodeDataTables" // libswiftUnicodeDataTables.a

For the simulator build, this seems to work:

try clang([
    "-nostdlib", "-dead_strip",
    "-Wl,-exported_symbol,_eventHandlerShim", "-Wl,-exported_symbol,_eventHandler",
    "-Wl,-L\(unicodeDataTablesPathSimulator),-l\(unicodeDataTablesLibName)",
    productSimulatorPath.string, "-dynamiclib", "-rdynamic", "-lm",
    "-DTARGET_SIMULATOR=1", "-DTARGET_EXTENSION=1",
    "-I", ".",
    "-I", "\(playdateSDK)/C_API",
    "-o", sourcePath.appending(["pdex.dylib"]).string,
    "\(playdateSDK)/C_API/buildsupport/setup.c"
])

However, the gcc build for device, does not:

try cc([setup, productDevicePath.string] + mcFlags + [
    "-Wl,-L\(unicodeDataTablesPathDevice),-Bstatic,-l\(unicodeDataTablesLibName)",
    "-T\(playdateSDK)/C_API/buildsupport/link_map.ld",
    "-Wl,-Map=\(context.pluginWorkDirectory.appending(["pdex.map"]).string),--cref,--gc-sections,--no-warn-mismatch,--emit-relocs",
    "-o", sourcePath.appending(["pdex.elf"]).string
])

(I've tried without -Bstatic as well as moving around the order of the arguments in case that would seem to matter 🙈.)

With the latter, I still see the compiler errors about failed linking:

(...)
.$ss7UnicodeO14_NFCNormalizerV7_resume12consumingNFDAB6ScalarVSgAH6scalar_AB9_NormDataV04normI0tSgADzXE_tF04$ss7a4O14_b21V6resume9consumingAB6f25VSgAIyXE_tFAH6scalar_AB9_hI20V04normH0tSgADzXEfU_AIIgd_Tf1cn_nTf4ng_n+0x112): undefined reference to `_swift_stdlib_getComposition'
/usr/local/playdate/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: //<compiler-generated>:(.text.$ss7UnicodeO14_NFCNormalizerV7_resume12consumingNFDAB6ScalarVSgAH6scalar_AB9_NormDataV04normI0tSgADzXE_tF04$ss7a4O14_b21V6resume9consumingAB6f25VSgAIyXE_tFAH6scalar_AB9_hI20V04normH0tSgADzXEfU_AIIgd_Tf1cn_nTf4ng_n+0x132): undefined reference to `_swift_stdlib_getComposition'
/usr/local/playdate/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: /Users/<home>/Projects/PDXSemiGameSwift/.build/plugins/PDCPlugin/outputs/Source/pdex.elf: hidden symbol `_swift_stdlib_getDecompositionEntry' isn't defined
/usr/local/playdate/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
[2K
[31m[1merror: [0mccFailed(exitCode: 1)

I've tried passing -Wl,--verbose to see if I can suss out what's happening but I'm just not familiar enough. I did manage to verify that ld seems to at least be finding the library correctly but I don't know enough to know why the linking still fails.

XCode build fails to produce .pdx, command line build works

Hello, and thanks for the great work on this!

I followed the setup instructions, and while swift package pdc indeed produces a pdx under the .build folder, building it in Xcode does not. Command-R completes without errors, but it launched the Playdate simulator without any file loaded because there is no PDX in the TARGET_BUILD_DIR directory.

Although I've gone over the steps a few times it's entirely possible I've missed something, but I'm not able to spot it.

Suggestion: Wrapping malloc/free-able resources in "RAII" classes on the Swift side

In @ricobeck's presentation today we looked at this part:

@discardableResult public func setSample(path: UnsafePointer<CChar>) -> Bool {
if let samplePointer {
sample.freeSample(samplePointer)
}
samplePointer = sample.load(path)
guard samplePointer != nil else { return false }
sampleplayer.setSample(playerPointer, samplePointer)
return true
}

Suggestion

What do you think about this:

We wrap a manually memory-managed object like "Sample" in a RAII (Resource Acquisition Is Initialization) class. (I know it's a C++ technique https://en.cppreference.com/w/cpp/language/raii but works with C as well to hide pointer mangement)

Before

 @discardableResult public func setSample(path: UnsafePointer<CChar>) -> Bool { 
     // Every change to self.sample needs to care about memory
     if let samplePointer { 
         sample.freeSample(samplePointer) 
     } 
  
     // Replacing can fail (but the other pointer is already gone)
     samplePointer = sample.load(path) 
     guard samplePointer != nil else { return false } 
  
     // Still using raw pointers after the load, also for playerPointer
     sampleplayer.setSample(playerPointer, samplePointer) 
     return true 
 } 

After

 @discardableResult public func setSample(path: UnsafePointer<CChar>) -> Bool { 
     guard let newSample = Sample(loadFromPath: path) else { return false }
     self.sample = newSample  
     newSample.withUnsafePointer { samplePointer in
        sampleplayer.setSample(playerPointer, samplePointer) 
     }
     return true 
 } 

Approach

Pseudoswift sketch:

final class Sample {
    private let pointer: OpaquePointer

    init?(loadFromPath path: UnsafePointer<CChar>) {
        let pointer = sample.load(path)
        guard pointer != nil else { return nil }
        self.pointer = pointer
    }

    deinit {
        sample.freeSample(pointer)
    }

    func withUnsafePointer(_ body: (OpaquePointer) -> Void) {
        body(pointer)
    }
}
  • Upside: if you have a Sample, your pointer is still alive, and we can use ARC to manage Sample's lifetime. So no calls to 'free' outside of where the opaque pointers are privately known.
  • Downside: It's another heap allocation.

XCode build (still) fails to produce .pdx, command line build works

I either can't re-open issues or can't figure out how, and I wasn't sure if there'd be a notice for a new comment in a closed issue so I'm opening a new one. Comment duplicated below:

Thanks for responding quickly! I tried your first suggestion, and tried building the unmodified PlaydateKit template project. The results were exactly the same, worked from the CLI but not from Xcode, the Simulator launched with no file loaded. Just like in my own project, this was the entire contents of TARGET_BUILD_DIR:
Mar 23 11:35 ./
Mar 23 11:35 ../
Mar 23 11:35 PackageFrameworks/
Mar 23 11:35 PlaydateKit.o
Mar 23 11:35 PlaydateKit.swiftmodule/
Mar 23 11:35 PlaydateKitTemplate.o
Mar 23 11:35 PlaydateKitTemplate.swiftmodule/

Then I pulled your latest changes. Same ultimate result, it still works from the CLI but not from Xcode; however, the Xcode behavior has changed as it now reports errors and doesn't launch the simulator. These are the console outputs from Command-R:
No matching processes belonging to you were found
Logging Error: Failed to initialize logging system. Log messages may be missing. If this issue persists, try setting IDEPreferLogStreaming=YES in the active scheme actions environment variables.
found Swift toolchain: org.swift.59202403191a
found Playdate SDK
�[2K
�[31m�[1merror: �[0mPlugin does not have access to a tool named ‘arm-none-eabi-gcc’
Program ended with exit code: 1

Originally posted by @cbackas42 in #14 (comment)

swift package pdc crashes

Just going through the setup docs and on the swift package pdc command I get errors about mismatched arch (I'm on an M1 Mac FWIW), and then it crashes.

I have TOOLCHAINS set:

export PLAYDATE_SDK_PATH=/Users/cove/Developer/PlaydateSDK
export TOOLCHAINS=org.swift.59202406081a

It appears to be discoverable:

% xcrun --toolchain $TOOLCHAINS  --find swiftc
/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-06-08-a.xctoolchain/usr/bin/swiftc

Here's the abbreviated output:

% swift package pdc 
warning: 'playdate2': remark: In-process target-info query failed (open("dlopen(/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-06-08-a.xctoolchain/usr/lib/swift/macosx/lib_InternalSwiftScan.dylib, 0x0105): tried: \'/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-06-08-a.xctoolchain/usr/lib/swift/macosx/lib_InternalSwiftScan.dylib\' (mach-o file, but is an incompatible architecture (have \'x86_64\', need \'arm64e\' or \'arm64\')), \'/System/Volumes/Preboot/Cryptexes/OS/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-06-08-a.xctoolchain/usr/lib/swift/macosx/lib_InternalSwiftScan.dylib\' (no such file), \'/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-06-08-a.xctoolchain/usr/lib/swift/macosx/lib_InternalSwiftScan.dylib\' (mach-o file, but is an incompatible architecture (have \'x86_64\', need \'arm64e\' or \'arm64\')), \'/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-06-08-a.xctoolchain/usr/lib/swift/host/lib_InternalSwiftScan.dylib\' (mach-o file, but is an incompatible architecture (have \'x86_64\', need \'arm64e\' or \'arm64\')), \'/System/Volumes/Preboot/Cryptexes/OS/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-06-08-a.xctoolchain/usr/lib/swift/host/lib_InternalSwiftScan.dylib\' (no such file), \'/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-06-08-a.xctoolchain/usr/lib/swift/host/lib_InternalSwiftScan.dylib\' (mach-o file, but is an incompatible architecture (have \'x86_64\', need \'arm64e\' or \'arm64\'))")). Using fallback mechanism.
[cut]
1.      Apple Swift version 6.0-dev (LLVM 579155491d559cc, Swift 64869e5a42221b2)
2.      Compiling with the current language version
3.      While evaluating request ExecuteSILPipelineRequest(Run pipelines { Mandatory Diagnostic Passes + Enabling Optimization Passes } on SIL for pladatekit_simulator)
4.      While running pass #5603 SILFunctionTransform "TransferNonSendable" on SILFunction "@$s20pladatekit_simulator8PlaydateO11playdateAPISo0cE0VSgvgZ".
 for getter for playdateAPI (at /Users/cove/Developer/playdate2/.build/checkouts/PlaydateKit/Sources/PlaydateKit/Playdate.swift:16:43)
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  swift-frontend           0x00000001073a88e8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 40
1  swift-frontend           0x00000001073a6dd5 llvm::sys::RunSignalHandlers() + 85
2  swift-frontend           0x00000001073a8f3e SignalHandler(int) + 270
3  libsystem_platform.dylib 0x00007ff8133befdd _sigtramp + 29
4  libsystem_platform.dylib 0x00007ff04a8f7018 _sigtramp + 18446744040278032472
5  libsystem_c.dylib        0x00007ff8132b5a79 abort + 126
6  libsystem_c.dylib        0x00007ff8132b4d68 err + 0
0  swift-frontend           0x000000010ace78e8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 40
7  swift-frontend           0x00000001077f3b43 swift::SILFunctionType::getSelfInstanceType(swift::SILModule&, swift::TypeExpansionContext) const (.cold.1) + 35
1  swift-frontend           0x000000010ace5dd5 llvm::sys::RunSignalHandlers() + 85
8  swift-frontend           0x00000001021b7781 swift::SILFunctionType::getSelfInstanceType(swift::SILModule&, swift::TypeExpansionContext) const + 161
2  swift-frontend           0x000000010ace7f3e SignalHandler(int) + 270
3  libsystem_platform.dylib 0x00007ff8133befdd _sigtramp + 29
4  libsystem_platform.dylib 0x00007fce8083f618 _sigtramp + 18446743895154361944
5  libsystem_c.dylib        0x00007ff8132b5a79 abort + 126
6  libsystem_c.dylib        0x00007ff8132b4d68 err + 0
[cut]
error: swiftcFailed(exitCode: 6)

Cannot add package dependency

Hi, is the a way to add a package dependency to the template?
If I add an external package or an internal target as dependency, Xcode recognize the dependency without error, but during compile I get always the "module XXX not found" error.
Am I missing something?

How do I use/cast `OpaquePointer` to `Sprite`?

I'm pretty excited about this library - and the instructions worked perfectly!

However I'm running into an issue (that may be my misunderstanding of how to use PlaydateKit!)

When I use setUpdateFunction on a sprite - the closure defaults to passing me a variable called sprite (which makes perfect sense - I probably want access to that sprite to do something with it) - but the type is OpaquePointer...

Is there a way to cast this into a PlaydateKit Sprite? What is the best way to use this?

Cannot set a Draw Function into a Sprite

Leaving this here in case you want to report a bug to the Swift team, if you get the chance to create a minimal repro
Otherwise I'm going to take a stab a it when I have some time

Using the PlaydateKitTemplate, adding the following code to the top
of the init() function in Game.swift

logoSprite.setDrawFunction(drawFunction: { sprite,bounds,drawRect in
    System.log("Draw function")
})

Produces the following error when compiling:

[...]
building playdatekittemplate_device.o
Assertion failed: (NextValue < Values.size()), function claimNext, file Explosion.h, line 136.
Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the crash backtrace.
Stack dump:
0.	Program arguments: /Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-03-13-a.xctoolchain/usr/bin/swift-frontend -frontend -c /Users/angelo/Projects/External/PlaydateKitTemplate/Sources/PlaydateKitTemplate/Game.swift /Users/angelo/Projects/External/PlaydateKitTemplate/Sources/PlaydateKitTemplate/entry.swift -target armv7em-none-none-eabi -disable-objc-interop -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.4.sdk -I /Users/angelo/Developer/PlaydateSDK/C_API -I /Users/angelo/Projects/External/PlaydateKitTemplate/.build/plugins/PDCPlugin/outputs/Modules -I /Users/angelo/Projects/External/PlaydateKitTemplate/.build/checkouts/PlaydateKit/Sources/CPlaydate/include -module-cache-path /Users/angelo/Projects/External/PlaydateKitTemplate/.build/plugins/PDCPlugin/outputs/module-cache -swift-version 6 -Osize -disable-stack-protector -function-sections -experimental-platform-c-calling-convention=arm_aapcs_vfp -enable-experimental-feature Embedded -module-alias PlaydateKit=playdatekit_device -empty-abi-descriptor -resource-dir /Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-03-13-a.xctoolchain/usr/lib/swift -Xcc -I -Xcc /usr/local/playdate/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/include -Xcc -I -Xcc /usr/local/playdate/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/include-fixed -Xcc -I -Xcc /usr/local/playdate/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/include -Xcc -DTARGET_EXTENSION -Xcc -mthumb -Xcc -mcpu=cortex-m7 -Xcc -mfloat-abi=hard -Xcc -mfpu=fpv5-sp-d16 -Xcc -D__FPU_USED=1 -Xcc -falign-functions=16 -Xcc -fshort-enums -module-name playdatekittemplate_device -plugin-path /Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-03-13-a.xctoolchain/usr/lib/swift/host/plugins -plugin-path /Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-03-13-a.xctoolchain/usr/local/lib/swift/host/plugins -enable-default-cmo -o /Users/angelo/Projects/External/PlaydateKitTemplate/.build/plugins/PDCPlugin/outputs/playdatekittemplate_device.o
1.	Apple Swift version 6.0-dev (LLVM d1625da873daa4c, Swift bae6450bf96dceb)
2.	Compiling with the current language version
3.	While evaluating request IRGenRequest(IR Generation for module playdatekittemplate_device)
4.	While emitting IR SIL function "@$s26playdatekittemplate_device4GameCACycfcys13OpaquePointerVSg_So6PDRectaAHtcfU_To".
 for expression at [/Users/angelo/Projects/External/PlaydateKitTemplate/Sources/PlaydateKitTemplate/Game.swift:7:50 - line:9:9] RangeText="{ sprite,bounds,drawRect in
            System.log("Draw function")
        "
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  swift-frontend           0x000000010842e754 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  swift-frontend           0x000000010842cf20 llvm::sys::RunSignalHandlers() + 112
2  swift-frontend           0x000000010842ed9c SignalHandler(int) + 304
3  libsystem_platform.dylib 0x000000018f8c1a24 _sigtramp + 56
4  libsystem_pthread.dylib  0x000000018f892cc0 pthread_kill + 288
5  libsystem_c.dylib        0x000000018f7a2a50 abort + 180
6  libsystem_c.dylib        0x000000018f7a1d6c err + 0
7  swift-frontend           0x0000000108489230 swift::irgen::emitForeignParameter(swift::irgen::IRGenFunction&, swift::irgen::Explosion&, swift::irgen::ForeignFunctionInfo, unsigned int, swift::SILType, swift::irgen::LoadableTypeInfo const&, swift::irgen::Explosion&, bool) (.cold.12) + 0
8  swift-frontend           0x0000000103381350 swift::irgen::emitForeignParameter(swift::irgen::IRGenFunction&, swift::irgen::Explosion&, swift::irgen::ForeignFunctionInfo, unsigned int, swift::SILType, swift::irgen::LoadableTypeInfo const&, swift::irgen::Explosion&, bool) + 1724
9  swift-frontend           0x00000001035335ec (anonymous namespace)::IRGenSILFunction::emitSILFunction() + 3328
10 swift-frontend           0x00000001035323a4 swift::irgen::IRGenModule::emitSILFunction(swift::SILFunction*) + 1524
11 swift-frontend           0x00000001033d7230 swift::irgen::IRGenerator::emitGlobalTopLevel(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>> const&) + 740
12 swift-frontend           0x00000001034e5208 swift::IRGenRequest::evaluate(swift::Evaluator&, swift::IRGenDescriptor) const + 2160
13 swift-frontend           0x00000001035318a4 swift::GeneratedModule swift::SimpleRequest<swift::IRGenRequest, swift::GeneratedModule (swift::IRGenDescriptor), (swift::RequestFlags)9>::callDerived<0ul>(swift::Evaluator&, std::__1::integer_sequence<unsigned long, 0ul>) const + 200
14 swift-frontend           0x00000001034eda78 swift::IRGenRequest::OutputType swift::Evaluator::getResultUncached<swift::IRGenRequest, swift::IRGenRequest::OutputType swift::evaluateOrFatal<swift::IRGenRequest>(swift::Evaluator&, swift::IRGenRequest)::'lambda'()>(swift::IRGenRequest const&, swift::IRGenRequest::OutputType swift::evaluateOrFatal<swift::IRGenRequest>(swift::Evaluator&, swift::IRGenRequest)::'lambda'()) + 212
15 swift-frontend           0x00000001034e62c8 swift::performIRGeneration(swift::ModuleDecl*, swift::IRGenOptions const&, swift::TBDGenOptions const&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::StringRef, swift::PrimarySpecificPaths const&, llvm::ArrayRef<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>, llvm::GlobalVariable**) + 1400
16 swift-frontend           0x0000000103000ba4 generateIR(swift::IRGenOptions const&, swift::TBDGenOptions const&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, swift::PrimarySpecificPaths const&, llvm::StringRef, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, llvm::GlobalVariable*&, llvm::ArrayRef<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>) + 272
17 swift-frontend           0x0000000102ffcdd4 performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) + 1416
18 swift-frontend           0x0000000102ffc4a0 swift::performCompileStepsPostSema(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 1164
19 swift-frontend           0x000000010300d430 withSemanticAnalysis(swift::CompilerInstance&, swift::FrontendObserver*, llvm::function_ref<bool (swift::CompilerInstance&)>, bool) + 160
20 swift-frontend           0x0000000102ffe88c performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 708
21 swift-frontend           0x0000000102ffd7f8 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 2368
22 swift-frontend           0x0000000102e17c74 swift::mainEntry(int, char const**) + 3096
23 dyld                     0x000000018f519058 start + 2224
building pdex.dylib
error: swiftcFailed(exitCode: 6)

Having an empty function or any code seems to produce the same or very similar error when compiling.

Missing stdlib

For some reason the "stdlib" (math.h, malloc.h, etc) isn't including properly when building, so the functions can't be used.

issues with new project setup

First off, thanks for making this, I think this goes a long way toward making this a viable path for Playdate games, and I'm super excited to get started with it!

This issue kind of goes hand-in-hand with #2, in that it's basically just about "How do I get started using this project?" I think that PR is part of a larger change that needs to get made to make the example project portable. Ideally a user should be able to copy the example out and rename some things, and have a new project... but that isn't really possible at present without a bunch of searching and replacing (and even after that there are some issues, I think). Alternatively, maybe there should be some detailed instructions on the "right" way to create a new project that works with this project as a dependency.

I said in Discord that I was going to open an issue about this topic, so this is it!

I was also planning to document everything I had to do to get a copy of BasicExample working, but I didn't document as well as I probably should have. Here are some of the issues I ran into:

  1. The make file specific to the swift package points up a directory at Examples/swift.mk.

    This is more or less what the PR addresses. My proposed solution is that we recommend everyone install PlaydateKit in a specific place on their machine. (Maybe along-side the PlaydateSDK, in ~/Developer?) This would allow Examples/swift.mk to hard-code that path value (ideally in a variable at the top, so a user can pretty easily change it if they want).

  2. For some reason, my copy of BasicExample had incorrect Schemes. I don't really know how this happened, but I needed to delete the extra schemes, and rename the BasicExample one (that was the only one that worked, since it ran build-and-run.sh), and built for release. The error I was getting at that point was: <unknown>:0: error: Whole module optimization (wmo) must be enabled with embedded Swift.

  3. It's worth noting that I had to replace even the names of the .o files in my new project's Makefile, because I'd previously run the basic example, and thus those files were cached. The Xcode console gave me some helpful warnings that the cached files did not match the working directory, but cleaning did not fix them.

  4. I still have an issue where my project seems to build and run correctly, but I have to manually open my .pdx file before it opens in the simulator. (The simulator does open, just not my project.) I can live with that, but it's annoying.

I'm not sure what the "fix" is for this issue. There are a lot of ideas, (a command-line utility was discussed), but it could just be that adequate documentation is the easiest path. On the other hand, I'm reluctant to start helping with documentation, since it's possible all of this will change, making any new project documentation obsolete.

docs directory causes build issues on Windows

It appears that PlaydateKit can't be cloned on a Windows machine because the documentation's information uses symbols that aren't allowed as file paths in Windows:

    error: unable to create file docs/data/documentation/playdatekit/graphics/drawbitmap(_:at:flip:).json: Invalid argument
    error: unable to create file docs/data/documentation/playdatekit/graphics/drawbitmap(_:at:xscale:yscale:).json: Invalid argument    
    error: unable to create file docs/data/documentation/playdatekit/graphics/drawellipse(in:linewidth:startangle:endangle:color:).json: Invalid argument
    error: unable to create file docs/data/documentation/playdatekit/graphics/drawline(_:linewidth:color:).json: Invalid argument       
    error: unable to create file docs/data/documentation/playdatekit/graphics/drawrect(_:color:).json: Invalid argument
    error: unable to create file docs/data/documentation/playdatekit/graphics/drawtext(_:at:).json: Invalid argument

Using git config --global core.protectNTFS seems to be ignored here as well. I recommend we convert the project's documentation website to use GitHub Actions to deploy the documentation live rather than hosting it in the docs dir.

Error ```swift package pdc``` on Windows

swift package pdc

error: plugin compilation failed: <PluginCompilationResult(
    succeeded: false,
    commandLine: C:\Users\tylerjaacks\AppData\Local\Programs\Swift\Toolchains\5.10.1+Asserts\usr\bin\swiftc.exe -L C:\Users\tylerjaacks\AppData\Local\Programs\Swift\Toolchains\5.10.1+Asserts\usr\lib\swift\pm\PluginAPI -lPackagePlugin -sdk C:\Users\tylerjaacks\AppData\Local\Programs\Swift\Platforms\5.10.1\Windows.platform\Developer\SDKs\Windows.sdk -libc MD -I C:\Users\tylerjaacks\AppData\Local\Programs\Swift\Platforms\5.10.1\Windows.platform\Developer\Library\XCTest-development\usr\lib\swift\windows -I C:\Users\tylerjaacks\AppData\Local\Programs\Swift\Platforms\5.10.1\Windows.platform\Developer\Library\XCTest-development\usr\lib\swift\windows\x86_64 -L C:\Users\tylerjaacks\AppData\Local\Programs\Swift\Platforms\5.10.1\Windows.platform\Developer\Library\XCTest-development\usr\lib\swift\windows\x86_64 -use-ld=lld -g -swift-version 5 -package-description-version 5.10.0 -I C:\Users\tylerjaacks\AppData\Local\Programs\Swift\Toolchains\5.10.1+Asserts\usr\lib\swift\pm\PluginAPI -parse-as-library -Xfrontend -serialize-diagnostics-path -Xfrontend D:\Desktop\PlaydateKitTemplate\.build\plugins\PDCPlugin\cache\PDCPlugin.dia D:\Desktop\PlaydateKitTemplate\.build\checkouts\PlaydateKit\Plugins\PDCPlugin\PDCPlugin.swift -o D:\Desktop\PlaydateKitTemplate\.build\plugins\PDCPlugin\cache\PDCPlugin.exe,
    executable: D:\Desktop\PlaydateKitTemplate\.build\plugins\PDCPlugin\cache\PDCPlugin.exe
    diagnostics: D:\Desktop\PlaydateKitTemplate\.build\plugins\PDCPlugin\cache\PDCPlugin.dia
    compilerOutput: "error: fatalError
error: emit-module command failed with exit code 1 (use -v to see invocation)
D:\Desktop\PlaydateKitTemplate\.build\checkouts\PlaydateKit\Plugins\PDCPlugin\PDCPlugin.swift:41:64: error: cannot call value of non-function type 'String'
    let home = FileManager.default.homeDirectoryForCurrentUser.path()
                                                               ^   ~~

D:\Desktop\PlaydateKitTemplate\.build\checkouts\PlaydateKit\Plugins\PDCPlugin\PDCPlugin.swift:317:52: error: no exact matches in call to initializer
                  let data = try? Data(contentsOf: URL(filePath: ""\(home)\(toolchainPath)/Info.plist"")),
                                                   ^
Foundation.URL:8:12: note: incorrect labels for candidate (have: '(filePath:)', expected: '(fileURLWithPath:)')
    public init(fileURLWithPath path: String)
           ^
Foundation.URL:2:12: note: incorrect labels for candidate (have: '(filePath:)', expected: '(fileReferenceLiteralResourceName:)')
    public init(fileReferenceLiteralResourceName name: String)
           ^
D:\Desktop\PlaydateKitTemplate\.build\checkouts\PlaydateKit\Plugins\PDCPlugin\PDCPlugin.swift:321:52: error: no exact matches in call to initializer
                  let data = try? Data(contentsOf: URL(filePath: ""/\(toolchainPath)/Info.plist"")),
                                                   ^
Foundation.URL:8:12: note: incorrect labels for candidate (have: '(filePath:)', expected: '(fileURLWithPath:)')
    public init(fileURLWithPath path: String)
           ^
Foundation.URL:2:12: note: incorrect labels for candidate (have: '(filePath:)', expected: '(fileReferenceLiteralResourceName:)')
    public init(fileReferenceLiteralResourceName name: String)
           ^
"
)>

Debug symbols aren't linked properly

Missing Swift module or Clang module found for "playdatekit_simulator", "imported" via SwiftDWARFImporterDelegate. Hint: Register Swift modules with the linker using -add_ast_path.

Inheritance of Sprite class

Hi! First of all great work on this!

Question: Is inheritance between classes something that is supported (or to be supported in the future)?

Right now I'm trying to make a subclass of the Sprite class, but I get this nasty error when trying to compile with swift package pdc

[...]
building pdex.elf
/usr/local/playdate/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/bin/ld: /Users/angelo/Projects/Swift/playdate/unicode-survivors/.build/plugins/PDCPlugin/outputs/unicodesurvivors_device.o:(.data+0xc): undefined reference to `$s18playdatekit_device8PlaydateO6SpriteOADC7pointerAFs13OpaquePointerV_tcfC'
collect2: error: ld returned 1 exit status
error: ccFailed(exitCode: 1)

Note: I had to mark the Sprite class as open in order to be able to subclass it

Retain classes from classes (Sprite.bitmap, Bitmap.mask, etc)

Currently you can set a Bitmap as a Sprite's image, but if you do not retain a reference to the Bitmap it will be deallocated and no longer display on the sprite. I think it would be nice if the class wrappers retained references to dependencies when logical.

No way of printing formatted string with floating numbers

Running

print("\(Display.refreshRate) FPS")

Will result in printing of (cannot print value in embedded Swift) FPS. It can be rounded to int but obviously it's not very handy if we want to print some smaller numbers or just need more precision and don't want to multiply it by 10^n. System->logToConsole could help but it's not fully implemented, unfortunately

Just a notice, I am new to swift so I can simply be mistaken. I can see a comment that logToConsole with formatting should be implemented but while it's not it seems there is no workaround to print numbers as default swift interpolation would say it's not allowed

I tried to see how to implement binding itself but unfortunately my knowledge of swift and especially embedded version simply does not let me do this

Improve the Pong example

  • Add a menu image
  • Add a title screen
  • Improve the computer player
  • Use the crank to move the paddle
  • Add sounds when a point is scored or the game ends
  • Use a better font
  • Speed up ball over time
  • Change ball angle based on where it hits the paddle

Discussion: Replacing or complementing `StaticString` with `String` in APIs

(Hello and thank you for all of your work on PlaydateKit, it's really great!)

I wanted to start a discussion around either 1) moving from StaticString to String now that some basic support has landed in Swift Embedded or if StaticString is still desirable (for performance/simplicity/memory/? reasons), 2) complementing any initializers/functions that accept StaticString with an overload for String.

I've been experimenting with this in my working fork of PlaydateKit and so far things seem to be working out pretty well. I'm curious to hear if there's interest in this, and if so, which direction would be preferred. If there's interest and a direction is determined, I would be happy to open pull requests and help move things along! Thanks for reading 🙏!

As just one example, for System.log():

Current

public static func log(_ log: StaticString) {
    let logToConsole = unsafeBitCast(
        system.logToConsole.unsafelyUnwrapped,
        to: (@convention(c) (UnsafePointer<CChar>?) -> Void).self
    )
    log.utf8Start.withMemoryRebound(
        to: CChar.self,
        capacity: log.utf8CodeUnitCount + 1
    ) { pointer in
        logToConsole(pointer)
    }
}

With String instead:

public static func log(_ log: String) {
    let logToConsole = unsafeBitCast(
        system.logToConsole.unsafelyUnwrapped,
        to: (@convention(c) (UnsafePointer<CChar>?) -> Void).self
    )

    // No idea if this is the best way to go about this, by the way!
    var utf8Log = log.utf8CString
    withUnsafeMutablePointer(to: &utf8Log[0]) { pointer in
        logToConsole(pointer)
    }
}

Which, of course, allows for potentially useful things like:

var message = ""
if Bool.random() {
  message = "Yay!"
} else {
  message = "Oh no!"
}

System.log("A logged message: \(message)")

(This is a silly example but a more concrete one is e.g. using a dynamically generated String as an argument to Graphics.Bitmap(path: ...) and I'm sure there are potentially many more!)

I can't build PlaydateKitTemplate

Summary

I can't build PlaydateKitTemplate.

How to reproduce

  1. Install Xcode 15.3
  2. Install Swift 6.0 Development toolchain
  3. Add /Library/Developer/Toolchains/swift-6.0-DEVELOPMENT-SNAPSHOT-2024-04-05-a.xctoolchain/usr/bin to $PATH
  4. Clone https://github.com/finnvoor/PlaydateKitTemplate
  5. Build with swift package pdc

Logs

$ swift package pdc
Fetching https://github.com/finnvoor/PlaydateKit.git from cache
Fetched https://github.com/finnvoor/PlaydateKit.git from cache (0.68s)
Creating working copy for https://github.com/finnvoor/PlaydateKit.git
Working copy of https://github.com/finnvoor/PlaydateKit.git resolved at main (b9a69fb)
found Swift toolchain: org.swift.600202404051a
found Playdate SDK
copying resources
building pladatekit_simulator.swiftmodule
building playdatekit_device.swiftmodule
/Users/kebo/PlaydateKitTemplate/.build/checkouts/PlaydateKit/Sources/PlaydateKit/Core/Display.swift:1:8: warning: public import of 'CPlaydate' was not used in public declarations or inlinable code
 1 | public import CPlaydate
   |        `- warning: public import of 'CPlaydate' was not used in public declarations or inlinable code
 2 | 
 3 | /// Functions pertaining to Playdate’s screen.

/Users/kebo/PlaydateKitTemplate/.build/checkouts/PlaydateKit/Sources/PlaydateKit/Core/Display.swift:1:8: warning: public import of 'CPlaydate' was not used in public declarations or inlinable code
 1 | public import CPlaydate
   |        `- warning: public import of 'CPlaydate' was not used in public declarations or inlinable code
 2 | 
 3 | /// Functions pertaining to Playdate’s screen.

/Users/kebo/PlaydateKitTemplate/.build/checkouts/PlaydateKit/Sources/PlaydateKit/Core/Sound.swift:1:8: warning: public import of 'CPlaydate' was not used in public declarations or inlinable code
  1 | public import CPlaydate
    |        `- warning: public import of 'CPlaydate' was not used in public declarations or inlinable code
  2 | 
  3 | /// Functions related to audio playback.

/Users/kebo/PlaydateKitTemplate/.build/checkouts/PlaydateKit/Sources/PlaydateKit/Core/Sound.swift:1:8: warning: public import of 'CPlaydate' was not used in public declarations or inlinable code
  1 | public import CPlaydate
    |        `- warning: public import of 'CPlaydate' was not used in public declarations or inlinable code
  2 | 
  3 | /// Functions related to audio playback.

/Users/kebo/PlaydateKitTemplate/.build/checkouts/PlaydateKit/Sources/PlaydateKit/Geometry/Rect.swift:1:8: warning: public import of 'CPlaydate' was not used in public declarations or inlinable code
 1 | public import CPlaydate
   |        `- warning: public import of 'CPlaydate' was not used in public declarations or inlinable code
 2 | 
 3 | // MARK: - Rect
building playdatekittemplate_simulator.o
/Users/kebo/PlaydateKitTemplate/.build/checkouts/PlaydateKit/Sources/PlaydateKit/Geometry/Rect.swift:1:8: warning: public import of 'CPlaydate' was not used in public declarations or inlinable code
 1 | public import CPlaydate
   |        `- warning: public import of 'CPlaydate' was not used in public declarations or inlinable code
 2 | 
 3 | // MARK: - Rect
building playdatekittemplate_device.o
building pdex.dylib
building pdex.elf
In file included from /Users/kebo/Developer/PlaydateSDK//C_API/buildsupport/setup.c:2:
/Users/kebo/Developer/PlaydateSDK//C_API/pd_api.h:13:10: fatal error: 'stdlib.h' file not found
   13 | #include <stdlib.h>
      |          ^~~~~~~~~~
1 error generated.
error: clangFailed(exitCode: 1)

Environment

$ sw_vers
ProductName:            macOS
ProductVersion:         14.4.1
BuildVersion:           23E224
$ which swift
/Library/Developer/Toolchains/swift-6.0-DEVELOPMENT-SNAPSHOT-2024-04-05-a.xctoolchain/usr/bin/swift
$ swift --version
Apple Swift version 6.0-dev (LLVM 3b959ba388a8ad9, Swift bb339b8f50f01fb)
Target: arm64-apple-macosx14.0
$ echo $TOOLCHAINS
org.swift.600202404051a

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.