libktx / ktx Goto Github PK
View Code? Open in Web Editor NEWKotlin extensions for the libGDX game framework
Home Page: https://libktx.github.io/
License: Creative Commons Zero v1.0 Universal
Kotlin extensions for the libGDX game framework
Home Page: https://libktx.github.io/
License: Creative Commons Zero v1.0 Universal
Skin
building methods.Array
, for example), as well as providing class names consistent with the factory methods.onKey() is all fine and well, but it has a couple of downsides.
The proposed functions would bind an InputListener with the onKeyDown() or onKeyUp() methods overriden.
Logger
implementation.Thanks to inline
functions, Kotlin can make it possible to use nearly-zero overhead logging mechanism that does not rely on varargs to provide string templates. The existing solution is - unfortunately - not compatible with LibGDX logging.
ktx-graphics
?Batch
and ShaderProgram
in ktx-app
.i'm gonna find some time to push some of my helper functions from my game upwards into here so other people can benefit from my headaches.
some of them are rather useful, some of them are useless even for me ( experiments ๐ )
i also have artemis ones that would be useful(delegate system initters and some other things), but i'll push that to the backburner because i want to see where i go with those
mostly the interface ones of libgdx, but there's a few others that might be useful to someone other than my crazy self, we'll have to see
the interfaces exist because if you have to inherit from it or create an object of it, it's waaay easier. since libgdx doesn't use default interface java keyword, meaning you have to implement everything. it also gives guarantees on nullability which i found annoying for some of them (like Actor?
but turns out it's never not null, so my kotlin wrappers give you that info back) and so on.
i'm sure i'll find ones in the future as i'm working and move them upwards where it makes sense.
there's also a couple in here https://github.com/sreich/ore-infinium/blob/master/core/src/com/ore/infinium/util/KotlinExtensions.kt (obvs ignore the ones that are clearly useless. mutableListOfNulls actually made it into stdlib in a form recently, i believe)
ones of interest are probably
any thoughts? care to take a glance and call out ones you think others might find useful, or use my best judgement and give a PR awaiting feedback on it?
Actor
extension methods for common listeners.Actor.isShown()
Actions
chaining methods (then
?) which automatically create action sequences.this is something that's been bothering me...
so you know how kotlin transforms get/set methods from java into property accessors. well, one place this screws up is in label and textbutton of scene2d.
label.text = "test" // won't work, can't assign string to stringbuilder
this exists because label has getText():StringBuilder, and setText(String)..which is a bit strange of an api to begin with.
in other words, from what i've seen, your only way of setting text is:
label.setText("")
the only workaround i could think of is something like this...(both textbutton and label are affected, not sure what else..haven't looked
private var Label.label: String
get() = text.toString()
set(str) = setText(str)
private var TextButton.label: String
get() = text.toString()
set(str) = setText(str)
got any better ideas? i really don't like the method syntax, property syntax is much more straightforward esp when everything else uses it (consistency). i have yet to find other properties that have similar problems.
build.gradle
file to Kotlin.build.gradle
files of subprojects.Because we can.
(Low priority.)
An equivalent to gdx-tools
that could automate some KTX-related operations. Potential candidates:
.properties
files to type-safe i18n enums from ktx-i18n
..json
definition to type-safe builders from ktx-style
.ktx-style
builders from an existing Skin
instance..atlas
files, which could be saved as a type-safe enum. Useful for both ktx-style
builders and general TextureAtlas
usage.Could be implemented as standalone library or Gradle plugin. Or both. The first approach seems the most flexible.
KWidget
(for all parental widgets)KTable
(for Table
-extending widgets)KTree
(for widgets operating on Tree.Node
instances)KGroup
(for regular WidgetGroup
actors)Table
-based (Table
, Window
, Dialog
, ButtonGroup
wrapper)Tree
WidgetGroup
-based (most other parental actors)Scene2D
widgets.
Actor
(should we even support this one?)Image
Label
List
(it's not exactly parental, a simple text adding extension method should be enough)ProgressBar
SelectBox
(similarly to list)Slider
TextArea
TextField
Touchpad
ButtonGroup
Button
CheckBox
Container
Dialog
HorizontalGroup
ImageButton
ImageTextButton
ScrollPane
SplitPane
Stack
Table
TextButton
Tree
(hierarchies should be supported somehow, each actor in a tree hierarchy might be a node)VerticalGroup
Window
TextTooltip
Tooltip
README
- overview of the supported features.
ApplicationAdapter
equivalent.Game
/Screen
equivalent.LetterboxingViewport
.README
, guide, usage examples).LibGDX default ApplicationListener
implementations are pretty basic and often force the user to set up boilerplate code like screen clearing or fixed rendering time step manually. This is desired for some advanced users, but most would like to focus on the game logic itself. A more advanced ApplicationListener
implementation that handles smooth view transitions and manages Stage
with a SpriteBatch
could be very useful.
master
branch testing.color
factory method with optional alpha
defaulting to 1f
.Color.copy
extension method, supporting optional values overriding.thinking clearscreen should instead have an optional arg for opacity. often times you want to set the opacity (fbos especially) and cannot do that. adding it as an optional arg should maintain BC (though i suppose that doesn't matter since ktx is not 1.0 yet)
Standard Gradle javadoc
task fails to build a proper Javadoc archive. However, we can use Dokka to generate Javadocs from Kotlin sources. It would be nice to automatically generate Dokka documentation and post it with GitHub Pages using the gh-pages
branch after every push to master.
KotlinApplication
's implementation of fixed timestep doesn't take interpolation/extrapolation between frames into account. For example, if the fixedTimeStep
is 0.05
, but the first Gdx.graphics.rawDeltaTime
is 0.08
, then it only calls render(0.05)
for one time. In the other words, it renders the state of the game at 0.05s, at the 0.08s of the real world.
It's not that bad, but we can at least let the user decide whether he wants interpolation/extrapolation for a smoother result.
Since KotlinApplication
doesn't expose timeSinceLastRender
, I have to copy&paste its code and implement my own ApplicationListener
this way:
override final fun render() {
timeSinceLastRender = Math.min(timeSinceLastRender + Gdx.graphics.rawDeltaTime, maxDeltaTime)
while (timeSinceLastRender >= fixedTimeStep) {
timeSinceLastRender -= fixedTimeStep
clearScreen(0f, 0f, 0f, 1f)
update(fixedTimeStep)
}
smoothRender(timeSinceLastRender / fixedTimeStep) // Extrapolation
}
ktx-vis-style
would a type-safe alternative to constructing VisUI styles with error-prone JSON files. See #13.
Vector2
.Vector3
.Matrix3
.Matrix4
.MathUtil
(?).Are you interested in adding helpers for Ashley? I have a few that might be a good fit for ktx.
cell
inCell
extension property returning Cell
storing the actor. Usable only in scope of KTable
parent.node
inNode
extension property returning Node
storing the actor. Usable only in scope of KTree
parent.cell
extension method allowing to customize Cell
storing the actor, returning the actor for fluent API. Usable only in scope of KTable
parent.node
extension method allowing to customize Node
storing the actor, returning the actor for fluent API. Usable only in scope of KTree
parent.Store actor's container using userObject
API of Actor
. Add scoped utility extension methods that allow to easily customize and access actor containers.
CHANGELOG.md
.1.9.4-b1
.libktx/ktx
.io.github.libktx
.Blocked by Maven Central procedures.
1.1.1 is now out, we can update to it.
KotlinTest is a promising testing framework that we can use to replace the current non-idiomatic JUnit tests. Mockito-Kotlin greatly improves mocking API and should be used instead of vanilla Mockito.
AssetManager
container.AssetDescriptor
building utilities.FileHandle
instances (an alternative to a rather obscure Gdx.files.internal
and so on).Disposable
utilities.Pool
utilities.Disposable
.Pool
.FileHandle
.Use Kotlin 1.1 @DslMarker
API to address scoping issues in ktx-scene2d
.
ktx-async
module.Gdx.app.postRunnable
to resume coroutines executed on other threads.AsyncExecutor
instance.HttpRequest
utilities based on coroutines.Timer
API. Currently it does not support lambdas.delay
method, which does not block the main rendering thread using LibGDX Timer
.skipFrame
suspending method that resumes on the next frame using Gdx.app.postRunnable
API.Implement ktx-async
module with asynchronous operations utilities and Kotlin 1.1 coroutines support.
nls
methods are not as useful.ktx-inject
, static access to resources can be harmful and hide code dependencies. Fully loaded assets should be passed directly to the objects and functions that depend on them.AssetManager
usage, allowing the users to migrate to the new API before the next release.ktx-i18n
documentation.ktx-inject
documentation.Most static variables are pretty much justified and optional to use. For example, you can still benefit from gdx-assets
utilities without the global AssetManager
, but most applications will want to use only a single one anyway.
I don't think the global Skin
variable should be removed from ktx-scene2d
though, as it greatly simplifies and improves readability of UI building methods.
@kotcrab @sreich @MrPlow442 I'd love to hear your thoughts on this.
ListViewStyle
support.HorizontalCollapsibleWidget
.See changelog.
nls
functions.I18NBundle
container.BundleLine
interface, providing i18n support with zero boilerplate.i'm working on the gradle plugin which will end up running a code generator on whatever we want (my focus is on fonts, sounds, textures not in particular order).
i could use some help on this issue right now. if you check out my fork, https://github.com/sreich/ktx/tree/feature/ktx-tools
running install on ktx-tools fails..not sure why it's failing at that task though. once i get this building a "hello world" then i can begin work on it. i'm inexperienced in gradle, but had it working fine before combining it into ktx-tools.
:tools:dokkaZip
:tools:compileKotlin UP-TO-DATE
:tools:compileJava NO-SOURCE
:tools:copyMainKotlinClasses FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':tools:copyMainKotlinClasses'.
> kotlin.KotlinNullPointerException (no error message)
* Try:
Run with --info or --debug option to get more log output.
* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':tools:copyMainKotlinClasses'.
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:84)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:55)
at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:88)
at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:46)
at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)
at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:236)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:228)
at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:61)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:228)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:215)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:77)
at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:58)
at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:32)
at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:113)
at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
at org.gradle.initialization.DefaultGradleLauncher$RunTasksAction.execute(DefaultGradleLauncher.java:256)
at org.gradle.initialization.DefaultGradleLauncher$RunTasksAction.execute(DefaultGradleLauncher.java:253)
at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:56)
at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:175)
at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:119)
at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:102)
at org.gradle.launcher.exec.GradleBuildController.run(GradleBuildController.java:71)
at org.gradle.tooling.internal.provider.runner.BuildModelActionRunner.run(BuildModelActionRunner.java:50)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.tooling.internal.provider.runner.RunAsBuildOperationBuildActionRunner$1.execute(RunAsBuildOperationBuildActionRunner.java:43)
at org.gradle.tooling.internal.provider.runner.RunAsBuildOperationBuildActionRunner$1.execute(RunAsBuildOperationBuildActionRunner.java:40)
at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:56)
at org.gradle.tooling.internal.provider.runner.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:40)
at org.gradle.tooling.internal.provider.runner.SubscribableBuildActionRunner.run(SubscribableBuildActionRunner.java:75)
at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:41)
at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:75)
at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:49)
at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:49)
at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:31)
at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:47)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
at org.gradle.util.Swapper.swap(Swapper.java:38)
at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:46)
Caused by: kotlin.KotlinNullPointerException
at org.jetbrains.kotlin.gradle.tasks.SyncOutputTask.siblingInJavaDir(SyncOutputTask.kt:162)
at org.jetbrains.kotlin.gradle.tasks.SyncOutputTask.siblingInJavaDir$default(SyncOutputTask.kt:161)
at org.jetbrains.kotlin.gradle.tasks.SyncOutputTask.processIncrementally(SyncOutputTask.kt:125)
at org.jetbrains.kotlin.gradle.tasks.SyncOutputTask.access$processIncrementally(SyncOutputTask.kt:57)
at org.jetbrains.kotlin.gradle.tasks.SyncOutputTask$execute$2.execute(SyncOutputTask.kt:93)
at org.jetbrains.kotlin.gradle.tasks.SyncOutputTask$execute$2.execute(SyncOutputTask.kt:57)
at org.gradle.api.internal.changedetection.changes.ChangesOnlyIncrementalTaskInputs.doOutOfDate(ChangesOnlyIncrementalTaskInputs.java:46)
at org.gradle.api.internal.changedetection.changes.StatefulIncrementalTaskInputs.outOfDate(StatefulIncrementalTaskInputs.java:39)
at org.gradle.api.internal.changedetection.changes.ChangesOnlyIncrementalTaskInputs.outOfDate(ChangesOnlyIncrementalTaskInputs.java:27)
at org.jetbrains.kotlin.gradle.tasks.SyncOutputTask.execute(SyncOutputTask.kt:93)
at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$IncrementalTaskAction.doExecute(DefaultTaskClassInfoStore.java:163)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:134)
at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:123)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:95)
at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:76)
... 78 more
Array
utilities: factory methods, extensions, Iterable
/kotlin.Array
conversions.ObjectSet
utilities: factory methods, extensions, Iterable
/kotlin.Array
conversions.ObjectMap
utilities.
Iterable
/kotlin.Array
conversions.map[key] = value
operator.PooledList
implementation: PooledLinkedList
done right.VisUI
widgets.
Actor
(maybe?)VisImage
VisLabel
VisList
VisProgressBar
VisSelectBox
VisSlider
VisTextArea
HighlightTextArea
ScrollableTextArea
VisTextField
VisValidatableTextField
Touchpad
BusyBar
Separator
LinkLabel
Button
VisCheckBox
VisRadioButton
VisDialog
VisWindow
)HorizontalGroup
HorizontalFlowGroup
VerticalGroup
VerticalFlowGroup
VisImageButton
VisImageTextButton
Stack
VisTable
VisTree
VisWindow
BasicColorPicker
ExtendedColorPicker
ToastTable
GridGroup
FloatingGroup
Spinner
ButtonGroup
Tooltip
(the VisUI one)MessageToast
MenuItem
(parental but adding something to menu items is usually not done since it disrupts popup menu layout)PopupMenu
(parental but MenuItem
must be added using its custom method)ListView
DragPane
/ Draggable
FormValidator
(not an actor but some API might be nice)TabbedPane
/ Tab
ButtonBar
VisScrollPane
(parental but standard addActor
is not supported)VisSplitPane
(parental but standard addActor
is not supported)MultiSplitPane
(parental but standard addActor
is not supported)Container
(parental but supports only single child)CollapsibleWidget
(parental but supports only single child)README
- overview of the supported features.INCOMPATIBLE with ktx-scene2d
to avoid collisions. Similarly named methods (for example, textButton
) might return different widgets in each library.
Asynchronous asset loading based on coroutines would both benefit simplify the API usage - it would look as if assets are loaded synchronously - as well as the asset manager internal implementation.
It would be possible to turn this pseudocode example:
fun create() {
assetManager.apply {
load<String>("my.txt") // Returns nothing. :C
load<Texture>("logo.png")
load<String>("other.txt")
load<I18NBundle>("i18n.properties")
// Schedule loading of other assets.
}
}
fun render() {
if (assetManager.update()) {
// Assets loaded!
finishLoading()
}
updateProgressLabel(assetManager.progress)
}
fun finishLoading() {
assetManager.apply {
myText = get<String>("my.txt")
logo = get<Texture>("logo.png")
otherText = get<String>("other.txt")
bundle = get<I18NBundle>("i18n.properties")
// Extract other assets.
}
goToNextView()
}
...into this pseudocode example:
fun create() {
assetManager.apply {
// Each call suspends and resumes on the rendering thread,
// never blocking the rendering process.
myText = load<String>("my.txt")
logo = load<Texture>("logo.png")
otherText = load<String>("other.txt")
bundle = load<I18NBundle>("i18n.properties")
}
// Resumes after all assets are loaded:
goToNextView()
}
fun render() {
updateProgressLabel(assetManager.statusMessage)
}
@kotcrab Thoughts on this? Should we include coroutines in ktx-assets
, add the new manager to ktx-async
(general LibGDX asynchronous operations utilities and basic coroutines support) or create a separate module?
ktx-style
ktx-style-vis
Use Kotlin 1.1 @DslMarker
API to address scoping issues in ktx-style
and ktx-style-vis
modules.
gdx-setup
.ktx-box2d
module.FixtureDef
factory methods supporting different shapes.earthGravity
property.World
factory methods.Fixture
instances.FixtureDef.filter
API.FixtureDef.shape
issue.userData
properties to extended body and fixture definitions.Basically, all KTX guides assume prior knowledge of LibGDX API. Some people are likely to get there because of Kotlin rather LibGDX. It would be nice to include some links to the original LibGDX APIs explanations that are being improved by each KTX module - for example, ktx-scene2d
could link to Scene2D wiki article.
Also, there is no CONTRIBUTING.md
file and Maven dependencies data in existing README
files.
.github
.README.md
.Contribution guide should contain a note about updating the changelog file and README
of the modified project.
Hi guys,
I am a little bit confused about the implementation of the math module.
Applying operators on vectors/matrices does not behave as expected since the result which gets returned is the left handed variable instead of a new vector/matrix.
For example:
val x = Vector2(1f, 1f)
val y = x * 2f
will get y
the correct result and x
won't be Vector2(1f, 1f)
anymore but Vector2(2f, 2f)
, i.e. x == y
is true
.
To bypass that problem you would do something like this: val y = Vector2(x) * 2f
so x
keeps it's original values.
I understand that the operators are simple aliases for the Vector/Matrix methods and the gdx implementation does not return new instances for obvious performance reasons.
So do you think this problem could be solved with some kind of pooling to prevent performance issues?
I would appreciate at least some kind of flag, which can be set for the math module so new instances get returned by default.
-Trixt0r
1.9.4-b1
version to Maven Central.README.md
with current version.This is attempt to improve current Vis builder API. Current implementation when building actors that belong to Table
-type widget will return Cell<Actor>
which is convenient if you need to modify cell properties but most of the time you also need to get Actor
itself which requires not so convenient .actor
call.
New API will introduce .cell {}
that will allow to modify Cell
properties but still return Actor
.
This requires to re-purpose Actor.userObject
for storing Cell. However .cell {}
syntax is only valid in UI builder, allowing user to re user field later. Also, fallback method searching actor hierarchy search would be implemented.
.cell {}
syntax is only valid in current DSL block thanks to two things:
Actor.userObject
provide API to call .cell{}
(thanks to possibility to put extension methods in interface)@DslMarker
annotationThis is simple subset of current API with those changes implemented. Notice that there is only one WidgetFactory
interface for both Table
-type and standard WidgetGroup
actors. Usage of @DslMarker
requires to extend all widget classes such as VisLabel
, that was not needed before.
inline fun table(init: KVisTable.() -> Unit): Table = actor(KVisTable(), init)
inline fun horizontalGroup(init: KHorizontalGroup.() -> Unit): KHorizontalGroup = actor(KHorizontalGroup(), init)
inline fun <T : Actor> actor(actor: T, init: T.() -> Unit): T {
actor.init()
return actor
}
@VisDslMarker
class KVisLabel(text: CharSequence, styleName: String) : VisLabel(text, styleName)
@VisDslMarker
class KVisTable : VisTable(false), WidgetFactory, CellAccessor {
override fun <T : Actor> addActorToWidgetGroup(actor: T): T {
val cell = add(actor)
actor.userObject = cell
return actor
}
}
@VisDslMarker
class KHorizontalGroup : HorizontalGroup(), WidgetFactory {
override fun <T : Actor> addActorToWidgetGroup(actor: T): T {
addActor(actor)
return actor
}
}
interface CellAccessor {
fun <T : Actor> T.cell(): Cell<T> {
return this.userObject as Cell<T> //TODO fallback to actor hierarchy search
}
fun <T : Actor> T.cell(initCell: Cell<T>.() -> Unit): T {
cell().initCell()
return this
}
// Alternatively to above
fun <T : Actor> T.cell(grow: Boolean, padding: Float = 0f /* other fields ...*/): T {
if (grow) cell().grow()
cell().pad(padding)
return this
}
fun <T : Actor> T.row(): T {
cell().row()
return this
}
@Deprecated("Calls to cell() can't be nested", level = DeprecationLevel.ERROR)
fun <T : Actor> Cell<T>.cell() {
}
@Deprecated("Calls to cell() can't be nested", level = DeprecationLevel.ERROR)
fun <T : Actor> Cell<T>.cell(initCell: Cell<T>.() -> Unit) {
}
}
interface WidgetFactory {
fun label(text: String, styleName: String = DEFAULT_STYLE, init: KVisLabel.() -> Unit = {}): VisLabel
= actor(KVisLabel(text, styleName), init)
fun table(init: KVisTable.() -> Unit = {}): VisTable = actor(KVisTable(), init)
fun horizontalGroup(init: KHorizontalGroup.() -> Unit = {}): HorizontalGroup = actor(KHorizontalGroup(), init)
fun <T : Actor> actor(actor: T, init: T.() -> Unit): T {
val result: T = addActorToWidgetGroup(actor)
actor.init()
return result
}
fun <T : Actor> addActorToWidgetGroup(actor: T): T
}
@DslMarker
annotation class VisDslMarker
Usage examples
fun createUI() {
var extLabel: VisLabel? = null
table {
extLabel = label("A")
val label: VisLabel = label("A") {
setAlignment(Align.left)
// cell {} // this is invalid because of DslMarker
}
val labelCell: Cell<VisLabel> = label("A").cell() // get cell explicitly
val label2: VisLabel = label("A").cell { growX() } // modify some values of cell but still get actor
val label4: VisLabel = label("A").cell(grow = true, padding = 2f) // alternative way to modify cell properties
horizontalGroup {
// both invalid because of DslMarker
// label2.cell()
// label("A").cell()
}
}
horizontalGroup {
val label: VisLabel = label("A")
//label("A").cell() // invalid, IDE won't suggest cell here
}
// invalid, IDE won't suggest cell here
//extLabel.cell()
//extLabel.cell { growX() }
}
@czyzby Any thoughts, do you see any shortcomings of this approach?
Skin
assets easier.ktx-style
would a type-safe alternative to constructing Scene2D styles with error-prone JSON files.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.