Git Product home page Git Product logo

gateengine's Introduction

GateEngine

A cross platform game engine for Swift that allows you to build 2D and 3D games.
GateEngine includes intuitive APIs for loading resources, handling user inputs, and rendering content.

Platform Support:

Platform CI Graphics Audio Keyboard Mouse Touch Gamepad
Windows¹ 5.8 ✔︎ ✔︎ ✔︎ ✔︎
macOS ✔︎ ✔︎ ✔︎ ✔︎ ✔︎ ✔︎
Linux² ✔︎ ✔︎ ✔︎ ✔︎ ✔︎
iOS/tvOS ✔︎ ✔︎ ✔︎ ✔︎iPadtvOS/iPhone ✔︎iOStvOS ✔︎
Android³
HTML5 ✔︎ ✔︎ ✔︎ ✔︎ ✔︎ ✔︎

Complete: ✔︎ | Incomplete: ⛌ | Partial: ◑
¹Windows support for Swift is in development. Latest Swift toolchain recommended.
²Developed and tested using Ubuntu (Debian). Fedora compatibility is unknown.
³Pending a community made cross compile SDK.
⁴Targeting recent versions of Safari, FireFox, Edge, and Chrome.

About

GateEngine is designed to give game developers access to approachable and intuitive APIs to code a game using Swift.

Math

GateEngine has a custom math library completely coded in Swift. GameMath allows developers to write math functions using a spoken language style API. GameMath uses context aware types like Position3, Direction3, and Size3. This adds an additional layer of understanding to APIs due to the inherent context each type provides.

let position: Position3 = Position3(0, 1, 0) * Size3(1, 1, 1)
...
let moved: Position3 = position.moved(units, toward: direction)
...
let reflected: Direction3 = direction.reflected(off: surfaceNormal)
...
let halfway = source.interpolated(to: destination, .linear(0.5))

Resources

GateEngine has a simple and intuitive resource loading and caching API. Resources can be constructed instantly and are non-blocking. The reference returned is a cache handle and creating multiple instances of the same resource will return the same cache handle. So you don't need to worry about managing your resources. You can simply create resources wherever you need.

// Load geometry
let geometry = Geometry(path: "model.obj")

// Reused the same cache as above. No load required.
let theSameGeometry = Geometry(path: "model.obj")

A resource state lets you know when a resource is ready to be used. In many situations the resource state is checked automatically, like when rendering. The renderer will automatically skip resources that aren't ready. But in some situations you may need to check the resource state manually.

let tileMap = TileMap(path: "tilemap.tmj")
...
if tileMap.state == .ready {
    // ready to be accessed
}

GateEngine tucks error handling away. A resource failing to load is usually a development error in games. It's not typically a runtime error that needs to be handled.

Writing do-try-catch for every resource would become tedious so GateEngine places errors in the resource state. This allows you to code the game as if the resource was a value type.

Resource errors are logged automatically so you don't usually need to check them.

[GateEngine] warning: Resource "tileSet.tsj" failedToLocate
[GateEngine] warning: Resource "tileMap.tmj" failedToLocate

But if you would like to design a fail-able resource handling mechanism, you can do so by checking for the error in the resource state.

if case .failed(let error) = resource.state {
    // This error was already output as a warning
}

Rendering

GateEngine uses a high level rendering API designed to be flexible and customizable. Rendering is done in the order things are added allowing you to easily reason about the outcome.

// Create a 2D draw container
var canvas = Canvas()

// Draw a sprite at a specific location 
canvas.insert(sprite, at: position)

// Draw the canvas inside the window
window.insert(canvas)

Advanced users can also leverage the lower level DrawCommand API for even more customizability.

Shaders

In most cases, shaders are handled automatically. However if you need to make a custom shader, GateEngine provides an easy and intuitive solution.

GateEngine uses a Swift based shader API that allows you to write your shaders directly within your project. The shaders automatically work on every platform, and there is no cross-compile tools or files to mess with.

// "Vertex Colors" vertex shader written in Swift
let vsh = VertexShader()
let mvp = vsh.modelViewProjectionMatrix
let vertexPosition = vsh.input.geometry(0).position
vsh.output.position = mvp * Vec4(vertexPosition, 1)
vsh.output["color"] = vsh.input.geometry(0).color

// "Tinted Texture" fragment shader written in Swift
let fsh = FragmentShader()
let sample = fsh.channel(0).texture.sample(
    at: fsh.input["texCoord0"]
)
fsh.output.color = sample * fsh.channel(0).color

Shaders are currently under development and are missing some functionality.

Getting Started

Add the package to your project like any other package.

.package(url: "https://github.com/STREGAsGate/GateEngine.git", .upToNextMinor(from: "0.1.0"))

iOS/tvOS require an Xcode project. You cannot use a Swift Package Manager executable for iOS or tvOS.

Windows Specific Setup

Swift 5.9.0-5.9.1 Only: A linker error for dinput.lib can be fixed with a workaround here.

Linux Specific Setup

For Linux you must install dev packages for OpenGL and OpenAL. On Ubuntu the following terminal commands will install the needed packages:

sudo apt-get update --fix-missing
sudo apt-get install freeglut3-dev
sudo apt-get install libopenal-dev

Examples

A suite of example projects is available at GateEngine Demos.
These examples cover a variety of topics including Rendering, User Input and Scripting.

Support GateEngine!

GateEngine relies on community funding. If you appreciate this project, and want it to continue, then please consider putting some currency into it. Every little bit helps!
Support With: GitHub, Ko-fi, or Patreon.

Community & Followables

A GateEngine development blog is published on Discord here.
Discord is also a great place to ask questions or show off your creations.

Discord Twitter YouTube Reddit

History

GateEngine started its life in 2016 as a "for fun" project that used the typical strategy, for hobby game engine projects, of high performance and small footprint. It used a scene graph and only worked on Apple devices using OpenGL.

Engine Creation 01

I created a deferred renderer, which is a technique that can reduce work for extremely complicated triple-A games. At the time I thought this was the greatest thing ever and I really enjoyed learning about.

Engine Creation 02

Then I added lighting, which was again a really fun learning process. Being able to see results on screen is very motivating and I'm sure that's why most game engines start out as graphics libraries.

Engine Creation 03

And then I added shadow and normal mapping.

Engine Creation 04

Eventually I added skinning and UI. And I created a 3D model of myself as a test. This is an early attempt at loading files from the COLLADA format. Something was still a little off, but I did eventually fix it 😜

Engine Creation 05

And I still needed to actually build the "engine" part. At this point the engine was just a graphics simulation. Drawing stuff is actually a fairly small portion of what a game engine does. I eventually learned about collision and different data techniques like Entity-Component-System.

And thats when I started the re-writes...

Developing an engine is a large learning process. Every time you come up with a good way to do it, you will come up with a better way before you're done implementing the previous way. At the beginning, iterations are complete rewrites and over time the iterations become more fine grained.

Slowly, my skill at making engines caught up to the designs I was creating and GateEngine began to stabilize. It was at this point that I realized I wasn't making any games. I was just building tech demos.

So I decided on my first 3D game. Espionage is a 3D stealth action game that I'm still working on today. It's inspired by the games I grew up with, and it's the kind of game I always wanted to make.

Espionage Screenshot

It's a very big project and it will likely take me a very long time to finish it as a solo developer. I personally prefer large projects.

I haven't yet been enticed to join a game jam, but perhaps that would be fun experience to try at some point. Maybe we'll have a GateJam someday!

Anyway, GateEngine was a massive undertaking, and was created to be enjoyed. So go make something awesome of your own!

gateengine's People

Contributors

gregcotten avatar heckj avatar strega 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  avatar  avatar

gateengine's Issues

Standardize Async Loading

Give Entity a state and allow users to check if it's completely loaded

Things that need loaded checking:

  • configure() blocks
    • Add a failure check for the async varient
  • components with resources
    • Give components a protocol to conform to

Design a LoadingSystem and LoadingSystemComponent with easy access to progress indicator and gracefully handles failure states.
Possibly use a LoadingDescriptionComponent to handle configuring an entity for loading itself.

Add OpenGL Rendering

Versions:

  • 4.0 Core
    • Shader Generator
    • Rendering

OS Support:

  • Ubuntu Linux
    • Main Window
    • Multiple Windows
  • macOS
    • Main Window
    • Multiple Windows

Add SwiftLint and configure for Style

Hi! Did not find any references to a linter and code style guides in the repo. It would be nice to have while the project does not become large and many other contributors joined the repository.

To not go too hard on a code style I would suggest using the existing one https://google.github.io/swift/ and for the linter SwiftLint. These two are battle-tested and used in many projects.

Feel free to close this issue without a response.

Add Shader Cache

Shaders are generated every launch. Speed up loading and reduce lag.

  • Generate IDs using a checksum
  • Async generate/compile shaders
    • WebGL2
    • OpenGL
    • Metal
    • DirectX 12
  • Cache generated shaders on platform FileSystem
    • WebGL2
    • OpenGL
    • Metal
    • DirectX 12

Audit Keyboard Inputs

Modifiers as actual keys for keyDown/keyUp
Add media keys (play, pause, etc...)
Add number pad
Differentiate key for controls and character for text input

  • Windows
  • macOS
  • Linux
  • iOS/tvOS
  • HTML5

Android Deferred #14

Build fails with many “No such module” errors

Build fails on macOS Sonoma 14.2.1 with Xcode 15.2 building for iOS/iPadOS 17.2 device with many repeated “No such module” many repeated errors looking for modules “DOM”, “ECMAScript”, & “JavaScriptEventLoop”. Issues seem to occur both on main (77889f0) and latest version tag (0.1.2) via both this repo and the GateEngineDemos repo (which pulls down GateEngine 0.1.2). Fresh git clone (I've never used GateEngine before today).

Mouse Lock Broken

Chrome doesn't appear to finish locking
Safari is reporting delta changes when the cursor doesn't move

FireFox is working correctly

2D_01_AnimatedSprite Demo Nof Working

I'm a Fedora user, running swift 5.8.1. The target shows as x86_64-unknown-linux-gnu.

When I run the 2D animation window the window is black with no animation. When I run it from the command line it presents 2 unhandled event warnings (21 and 19) and I don't know if that's significant.

I'm not understanding how resource pathing works. I see the "Earth rotating 32 x 32.png' file, and I see it referenced from a relative path of "Resources/Earth rotating 32 x 32.png", from the Source location, but don't know how the engine uses this information, in relationship to the executable under the target directory for my platform. I get the same result when attempting to do "swift run 2D_01_AnimatedSprite".

I apologize if this is a new user error and would appreciate some direction if this isn't a bug. None of the demos are displaying anything. The multiple windows examples open windows, but they're all blank.

I also have a Win 10 system, so I'm tempted to install swift to work with the demos there to compare the behaviors.

Thanks!

Audit Gamepad Inputs

Interpreters

  • windows
  • macOS/iOS/tvOS
    • MFi Gamepad Interpreter
  • macOS
    • HID (SDL2 Database)
  • Linux
    • HID (SDL2 Database)

Rework File Importers

TODO:

  • Temporarily Cache any importer object
    - Some can load multiple things from the same file, causing the file to be reloaded multiple times.

New Importers

  • #44
  • FBX Skin
  • FBX Texture
  • glTF Texture
  • Apple ModelIO Geometry
  • Apple ModelIO Skin
  • Apple CoreImage Texture

Shader API

Rework Shader API for public consumption.

  • Use a result builder for shader construction
  • Attempt to prevent instance dependent build objects from being used on other shader instances at the compile stage.
    • These objects include custom uniforms, buffer attachments, and buffer destinations.
    • Type constraints?
  • Give shaders a unique identifier that will allow for static caching of generated/built shaders.
  • Give shaders the ability to be changed at runtime and auto recompile, even while being used.
    • Possibly with a MutableXXXXXShader type variant as these won't be cacheable.
  • Fully document and include examples as markdown sheets in SwiftDocC library.

User Interface API

Design:
Support standard views and controls. Users should be able to easily build complex apps.

Standard MVC Hierarchy:

  • ViewControllers (as Systems?)
  • Nest-able Views
  • Constraint Layout

Should also have a SwiftUI style API so GateEngine can easily be used for things like companion apps, or custom level editors.

Strip Foundation imports

Currently every supported platform supports Foundation, but Bare Metal is coming and probably won't.
Confine Foundation to Platform instances and replace it's functionality with abstractions.

  • Add @_exported import for Data and URL to GateEngine.swift
    • we'll use SwiftFoundation for these when it's ready
  • GameMath uses sin functions. Look into implementing native ones, possibly in C/C++
    C and C++ standard libraries both have sin functions, so Foundation should always have them.

Audio Audit

  • macOS/iOS/tvOS
  • Positional Sounds
  • Multitrack Music
  • Fading In/Out
  • Windows
  • Positional Sounds
  • Multitrack Music
  • Fading In/Out
  • Linux
  • Positional Sounds
  • Multitrack Music
  • Fading In/Out
  • HTML5
  • Positional Sounds
  • Multitrack Music
  • Fading In/Out

Documentation Audit

  • Full public API DocC coverage
  • Refactor all SwiftLint errors and warnings

Special DocC Pages

  • Explain in detail: Game Lifecycle
  • Explain in detail: Window Management
  • Explain in detail: Entity, Component, System
  • Explain in detail: Resource Loading, Lifecycle (Cache)
  • Explain in detail: Custom File Importers
  • Explain in detail: Audio Playback
  • Explain in detail: Rendering
  • Explain in detail: UserInput

SaveState Audit

GateEngine

  • Key Value Store API with namespaces
    • Lock to explicit type (Bool, Int, UInt, Double, String, etc...)
    • Consider future cloud services compatibility
  • File I/O through File System Abstraction
    • Allow Data and any Codable
    • Allow specifiable path
  • #28
    • Replace Data.init(contentsOf:) usage

Platforms

  • macOS
    • Native File System Abstraction
    • Push SaveState through FileSystem
  • iOS/tvOS
    • Native File System Abstraction
    • Push SaveState through FileSystem
  • HTML5
    • Native File System Abstraction
    • Local Storage StateState wo/ Secure Context
    • Push SaveState through FileSystem w/ Secure Context
  • Windows
    • Native File System Abstraction
    • Push SaveState through FileSystem
  • Linux
    • Native File System Abstraction
    • Push SaveState through FileSystem

Audit Platform Window

  • macOS
    • interfaceScale updates with user preference
    • size in pixels and points
    • Resize does reshape
    • Can open multiple windows
  • iOS/tvOS
    • interfaceScale updates with user preference
    • size in pixels and points
    • Resize does reshape
    • Can open multiple windows on iPadOS
  • Windows
    • interfaceScale updates with user preference
    • size in pixels and points
    • Resize does reshape
    • Can open multiple windows
  • Linux
    • interfaceScale updates with user preference
    • size in pixels and points
    • Resize does reshape
    • Can open multiple windows
  • HTML5
    • interfaceScale updates with user preference
    • size in pixels and points
    • Resize does reshape

Rework Skeletal Rig/Animation

Skeletal animations and RigSystem are cumbersome and difficult to use. Rework into something more friendly and approachable.

Gravity Tests Crash on HTML5

The test executable crashes during tests involving Gravity scripts at WASIPlatform.fetch()
Deferring solving this bug until it gets hit in a GateEngine project where more information might be available in output.

Debugging Discoveries
The crash occurs after JSPromise.value returns and before the retuned value is stored.

Thoughts:

  • The debugging results could indicate an exception on another thread
  • Sometimes fetch does return once, so again probably a threading issue
  • SwiftWASM doesn't support threading, but does use a Javascript worker.

The crash trace:

<?>.wasm-function[swift_task_asyncMainDrainQueueImpl()]@[wasm code]
<?>.wasm-function[swift_task_asyncMainDrainQueue]@[wasm code]
<?>.wasm-function[XCTMainRunLoopMain]@[wasm code]
<?>.wasm-function[$s6XCTest7XCTMain_9arguments9observersySayAA0A4CaseCm04testE5Class_SaySS_yAFKctG8allTeststG_SaySSGSayAA0A11Observation_pGtF]@[wasm code]
<?>.wasm-function[$s6XCTest7XCTMainyySayAA0A4CaseCm04testC5Class_SaySS_yADKctG8allTeststGF]@[wasm code]
<?>.wasm-function[$s22GateEnginePackageTests6RunnerV4mainyyFZ]@[wasm code]
<?>.wasm-function[$s22GateEnginePackageTests6RunnerV5$mainyyFZ]@[wasm code]
<?>.wasm-function[main]@[wasm code]
wasm-stub@[wasm code]
49869@[native code]
@http://127.0.0.1:8080/test.js:8948:30

Tests involving gravity are disabled on HTML5 using a package define DISABLE_GRAVITY_TESTS

Audit Mouse Inputs

GateEngine API

  • Create Scroll API (Ticks, Smooth)
  • Mouse mode API (standard, locked)
  • Multi-Click Gestures

Platform Audit

  • Windows
    • Mouse Buttons (1, 2, 3, 4, 5)
    • Mouse Hide/Unhide
    • Mouse Set Position
    • Scroll Ticks (x, y)
    • Scroll Smooth (x, y)
    • Multi-Click User Time
  • macOS
    • Mouse Buttons (1, 2, 3, 4, 5)
    • Mouse Hide/Unhide
    • Mouse Set Position
    • Scroll Ticks (x, y)
    • Scroll Smooth (x, y)
    • Multi-Click User Time
  • Linux
    • Mouse Buttons (1, 2, 3, 4, 5)
    • Mouse Hide/Unhide
    • Mouse Set Position
    • Scroll Ticks (x, y)
      Scroll Smooth (x, y)
      Multi-Click User Time
  • iOS/tvOS
    • Mouse Buttons (1, 2, 3, 4, 5)
    • Mouse Hide/Unhide
    • Mouse Set Position
      Scroll Ticks (x, y)
      Scroll Smooth (x, y)
      Multi-Click User Time
  • HTML5
    • Mouse Buttons (1, 2, 3, 4, 5)
    • Mouse Hide/Unhide
    • Mouse Lock/Unlock
    • Scroll Ticks (x, y)
      Scroll Smooth (x, y)
      Multi-Click User Time

Android Deferred #16

Add Gravity Scripting

Add Gravity as GateEngine's scripting language.

  • #33
  • Create shared modules to hook into GateEngine
    • GameMath types and functions
    • Game, Entity, System functions
    • AudioSystem hooks
    • HID hooks

Add XAudio Backend

XAudio2 is C++ only. Going to give Windows OpenAL as a fallback while C++ Interop is completed.

Graphics Audit v1.1.0

Rendering

  • #19
  • RenderTarget destinations
    • ColorN, Depth, Stencil
  • RenderTarget Options
    • DepthFailDiscard
    • StencilFailDiscard
  • 3D Lighting
    • Point, Spot, Directional

APIs

Bug Fixes

Audit Android Mouse Inputs

  • Mouse Buttons (1, 2, 3, 4, 5)
  • Mouse Hide/Unhide
  • Mouse Lock/Unlock
  • Scroll Ticks (x, y)
  • Scroll Smooth (x, y)

FBX Geometry Importer

Create a new GeometryImporter for FBX files.
This is a moderate difficulty issue.
If you have no experience working with geometry data there will be a learning curve.

Use the uFBX module which is already a part of GateEngine.
import uFBX

Name this new importer FBXImporter.

Add your loader to the geometry importers here. This is where built-in importers are located.

Use only GateEngine APIs for data loading, do not use any file APIs included in the uFBX module.
See the OBJ loader as an example of how a geometry importer works.

Use Blender to create an FBX file to test with. It can simply be the default cube or whatever you wish.

Create an executable package to test with. It would be easy to copy the RotatingCube code to your test package and replace the cube with your fbx test file.

Xcode Tip:
In Xcode if your project package and the GateEngine package exist in the same xcworkspace document, then it will build with that local copy of GateEngine as you make changes.
Make a new workspace in Xcode then open your package in Xcode, and drag the package icon into the workspace.
Repeat for your GateEngine fork.
Dragging the Package.swift file does not work, you need to open it then drag the package icon in the project navigator.

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.