An attempt to make a purely functional game engine, using ZIO effects and an ECS architecture, which would be extremely simple and convenient to build scalable games fast. Convenience and game development speed are the main goals of this project.
Currently work in progress.
Add the following to your build.sbt inside project settings:
resolvers += "jitpack" at "https://jitpack.io",
libraryDependencies += "com.github.optical002" % "aether-flow" % "0.0.1"package game
import engine.*
import engine.ecs.*
import engine.graphics.*
import engine.graphics.config.WindowConfig
import engine.graphics.opengl.API
import engine.graphics.opengl.shaders.StandardShader
import engine.core.logger.ASyncLogger
import zio.*
object GameMain extends App {
override lazy val configs: WindowConfig = new WindowConfig {
val title = "Game from Scala FP"
val width = 800
val height = 600
val frameRate = 60
}
override def graphicsAPI(): GraphicsAPI = API
override def render(db: GraphicDatabase): Task[Unit] = for {
_ <- db.load(GraphicAsset(VertexData.Quad, StandardShader))
} yield ()
override def startupWorld(
builder: WorldBuilder
): WorldBuilder = builder
.addStartUpSystem(StartUpSystem)
.addSystems(priority = 0, MovementSystem)
.addSystems(priority = 1, LogSystem)
override def enableMetrics: Boolean = false
}
object StartUpSystem extends System {
override def run(world: World, logger: ASyncLogger): Task[Unit] =
world.createEntity(Transform(0, 0), Velocity(1, 1))
*> logger
.logDebug("Created entity")
}
object LogSystem extends ecs.System {
override def run(world: World, logger: ASyncLogger): Task[Unit] = for {
result <- world.query2[Transform, Velocity]
strings <- ZIO.foreach(result) { case (e, transformRef, velocityRef) =>
for {
transform <- transformRef.get.commit
velocity <- velocityRef.get.commit
} yield s"Entity($e), $transform, $velocity"
}
_ <- logger.logDebug(
s"Entities queried: ${result.length}, [\n ${strings.mkString(",\n ")}\n]"
)
} yield ()
}
object MovementSystem extends ecs.System {
override def run(world: World, logger: ASyncLogger): Task[Unit] = for {
result <- world.query2[Transform, Velocity]
_ <- ZIO.foreach(result) { case (_, transformRef, velocityRef) =>
for {
velocity <- velocityRef.get.commit
_ <- transformRef.update(_.applyVelocity(velocity)).commit
_ <- logger.logDebug("Moved transform by velocity")
} yield ()
}
} yield ()
}Note: If somehting does not work or break, you can look up example projects which are built with specific versions inside my 'aether-flow-examples' repository.
- Create
plugins.sbtinsideprojectdirectory and add following
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.3")- In
build.sbtinside project settings add main entry point of the game (replace"Main"with your main class name)
assembly / mainClass := Some("Main"),
assembly / assemblyMergeStrategy := {
case PathList("META-INF", xs @ _*) => MergeStrategy.discard
case x => MergeStrategy.first
},- To install build tools run this from powershell
iwr -useb https://github.com/optical002/aether-flow-tooling/releases/download/build-tools-v0.1.0/install.ps1 | iex- To build execute
build.ps1, when working with multiproject layout add-p project-nameor--project project-name