简体   繁体   English

Clojure与libgdx互操作到Java

[英]clojure to java interop with libgdx

I'm trying to reproduce the sample app from this libgdx tutorial in clojure and am having a hard time getting the java interop part working. 我试图从Clojure的libgdx教程中重现示例应用程序,并且很难使Java互操作部件正常工作。

The way a desktop game is created in libgdx is by instantiating the LwjglApplication class with an object that implements the ApplicationListener interface, along with some configuration options, like so: 在libgdx中创建桌面游戏的方式是通过实例化LwjglApplication类,该对象实现了ApplicationListener接口以及一些配置选项,例如:

import com.badlogic.gdx.backends.lwjgl.LwjglApplication;

public class Main {

  public static void main(String[] args) {
    new LwjglApplication(new DropGame(), cfg);
  }

  public class DropGame implements ApplicationListener {
    Texture dropImage;
    Sound dropSound;     
    ... rest of assets 

    public void create() {
      dropImage = new Texture(Gdx.files.internal("droplet.png"));
      dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
    }
    ... rest of interface methods

  }
}

After reading up on clojure/java interop, here is the clojure equivalent I came up with: 阅读了clojure / java interop之后,这是我想出的clojure等效项:

(ns dropgame.core
  (:gen-class)
  (:import (com.badlogic.gdx.backends.lwjgl LwjglApplication))

(defn app-listener [] 
    (reify ApplicationListener
      (create [this] (let [dropImage (Texture.            (.internal Gdx/files "droplet.png"))
                           dropSound (.newSound Gdx/audio (.internal Gdx/files "drop.wav"))])

(defn App [] 
  (LwjglApplication. (app-listener) cfg))

I left out a lot of the code, but that's fine because the app works using this structure. 我省略了很多代码,但这很好,因为该应用程序使用此结构工作。 The problem is that this code is not exactly the same. 问题在于此代码不完全相同。 The libgdx framework chooses to declare all assets globally (dropImage and dropSound in this case) so that code in other methods has easy access to them without needing to pass them around. libgdx框架选择全局声明所有资产(在这种情况下为dropImage和dropSound),以便其他方法中的代码可以轻松访问它们而无需传递它们。 If I try to restructure my code to do the same, by declaring assets in an outer let binding instead of inside a method, it no longer works. 如果我尝试通过在外部let绑定中而不是在方法内部声明资产来重组代码以执行相同的操作,则该代码将不再起作用。

Doing this gives me a nullPointerException: 这样做给了我一个nullPointerException:

(defn app-listener [] 
  (let [dropImage (Texture.            (.internal Gdx/files "droplet.png"))
        dropSound (.newSound Gdx/audio (.internal Gdx/files "drop.wav"))]
    (reify ApplicationListener
      (create [this] ( ; try accessing dropImage or dropSound)))))

So the let binding is creating the same objects, but accessing these object from inside any of the methods no longer seems to work. 因此,let绑定正在创建相同的对象,但是从任何方法内部访问这些对象似乎不再起作用。 Any ideas what I'm doing wrong here? 有任何想法我在这里做错了吗?

EDIT: So as mentioned, the reason why I was getting a nullPointerException is probably because the assets were being loaded before the app was ready. 编辑:因此,如上所述,我之所以得到nullPointerException的原因可能是因为在应用程序准备就绪之前就已加载资产。 But anyway the proper way to load assets for anything beyond a simple game is to use the AssetManager, as muhuk suggested. 但是无论如何,如muhuk所建议的那样,为简单游戏之外的任何事物加载资产的正确方法是使用AssetManager。 So I ended up doing something like this for assets: 因此,我最终对资产执行了以下操作:

(def asset-manager (doto (AssetManager.)
                   (.load "rain.mp3"    Music)
                   (.load "droplet.png" Texture))

However there are other things besides assets that need to be accessed globally, for example the camera. 但是,除了资产之外,还有其他一些东西需要全局访问,例如摄像机。 So what I did for these is this: 所以我为此做的是:

(defn app-listener []
  (reify ApplicationListener
    (create [this]
      (def camera (-> (OrthographicCamera.) (.setToOrtho false 800 480)))))) 

While this would probably raise alarms in any normal clojure code, since you have a function defining global values, in this particular case it actually makes sense since 'app-listener' is only getting instantiated once, and the documentation specifies that the 'create' method only gets called once too during the app's life cycle. 尽管这可能会在任何普通的clojure代码中引发警报,但是由于您具有定义全局值的函数,因此在这种特殊情况下,这实际上是有意义的,因为“ app-listener”仅实例化一次,并且文档指定“ create”方法在应用程序的生命周期中也只会被调用一次。 Though I'd still like to know if there's a better way to do this. 虽然我仍然想知道是否有更好的方法可以做到这一点。

As for using 'deftype', my understanding is that 'defrecord' would be easier to use since it allows for passing a map of additional fields without having to declare them in the constructor. 至于使用“ deftype”,我的理解是“ defrecord”将更易于使用,因为它允许传递附加字段的映射而不必在构造函数中声明它们。 But in either case the code ended up looking pretty messy since you have to pass all your assets to the constructor. 但无论哪种情况,代码最终看起来都非常混乱,因为您必须将所有资产传递给构造函数。 In addition to that, defining a named type kind of obscures what the code is doing and doesn't fit very nicely with the problem. 除此之外,定义一种命名类型会掩盖代码的作用,并且无法很好地解决该问题。

I'm gonna finish up the rest of the tutorial and post a link to the clojure code once I'm done. 我将完成本教程的其余部分,并在完成后发布指向Clojure代码的链接。 Thanks guys. 多谢你们。

My guess is you're trying to initialize them before they are allowed to be initialized by the libgdx framework. 我的猜测是您正在尝试在libgdx框架允许对其进行初始化之前对其进行初始化。 would be helpful if you posted a stack trace. 如果您发布了堆栈跟踪信息将很有帮助。

As another clojure newbie, maybe the thing to do is explore deftype? 作为另一个clojure新手,也许要做的事情就是探索deftype? iirc that would give you methods and fields, which is what you need. iirc将为您提供所需的方法和字段。 let initializes a variable to the current scope only. let仅将变量初始化为当前作用域。

Another approach might be binding the values current thread, but i'm not sure what would be more correct. 另一种方法可能是绑定当前线程的值,但是我不确定哪个更正确。 Good luck! 祝好运! (I'm also interested in libgdx and clojure) (我也对libgdx和clojure感兴趣)

That let would try to load the assets before an application instance is created. let想尝试创建一个应用程序实例之前加载的资产。 libGDX mimics the android application lifecycle so you shouldn't try loading assets before create is called. libGDX模仿了android应用程序的生命周期,因此您不应在调用create之前尝试加载资产。

Since libGDX is a Java framework we can't expect it to match Clojure's purely functional approach. 由于libGDX是Java框架,我们不能期望它与Clojure的纯功能方法相匹配。 There's got to be some state somewhere. 某处必须有某种状态。 You might want to take a look at the AssetManager . 您可能想看看AssetManager

In case people having trouble with Clojure and the example game end up here (like I did), here's a link to a working implementation (without the music / sounds though): 如果有人对Clojure有麻烦,并且示例游戏到这里结束了(就像我所做的那样),这是一个可行的实现的链接(尽管没有音乐/声音):

http://clojuregames.blogspot.com/2013/10/the-libgdx-simple-game-demo-in-clojure.html http://clojuregames.blogspot.com/2013/10/the-libgdx-simple-game-demo-in-clojure.html

I'm still only beginning to learn Clojure as well, so in case some things in the implementation are done in a bad way, let me know in the comments. 我仍然还只是开始学习Clojure,所以如果实现中的某些事情做得不好,请在评论中告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM