繁体   English   中英

Clojure与libgdx互操作到Java

[英]clojure to java interop with libgdx

我试图从Clojure的libgdx教程中重现示例应用程序,并且很难使Java互操作部件正常工作。

在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

  }
}

阅读了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))

我省略了很多代码,但这很好,因为该应用程序使用此结构工作。 问题在于此代码不完全相同。 libgdx框架选择全局声明所有资产(在这种情况下为dropImage和dropSound),以便其他方法中的代码可以轻松访问它们而无需传递它们。 如果我尝试通过在外部let绑定中而不是在方法内部声明资产来重组代码以执行相同的操作,则该代码将不再起作用。

这样做给了我一个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)))))

因此,let绑定正在创建相同的对象,但是从任何方法内部访问这些对象似乎不再起作用。 有任何想法我在这里做错了吗?

编辑:因此,如上所述,我之所以得到nullPointerException的原因可能是因为在应用程序准备就绪之前就已加载资产。 但是无论如何,如muhuk所建议的那样,为简单游戏之外的任何事物加载资产的正确方法是使用AssetManager。 因此,我最终对资产执行了以下操作:

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

但是,除了资产之外,还有其他一些东西需要全局访问,例如摄像机。 所以我为此做的是:

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

尽管这可能会在任何普通的clojure代码中引发警报,但是由于您具有定义全局值的函数,因此在这种特殊情况下,这实际上是有意义的,因为“ app-listener”仅实例化一次,并且文档指定“ create”方法在应用程序的生命周期中也只会被调用一次。 虽然我仍然想知道是否有更好的方法可以做到这一点。

至于使用“ deftype”,我的理解是“ defrecord”将更易于使用,因为它允许传递附加字段的映射而不必在构造函数中声明它们。 但无论哪种情况,代码最终看起来都非常混乱,因为您必须将所有资产传递给构造函数。 除此之外,定义一种命名类型会掩盖代码的作用,并且无法很好地解决该问题。

我将完成本教程的其余部分,并在完成后发布指向Clojure代码的链接。 多谢你们。

我的猜测是您正在尝试在libgdx框架允许对其进行初始化之前对其进行初始化。 如果您发布了堆栈跟踪信息将很有帮助。

作为另一个clojure新手,也许要做的事情就是探索deftype? iirc将为您提供所需的方法和字段。 let仅将变量初始化为当前作用域。

另一种方法可能是绑定当前线程的值,但是我不确定哪个更正确。 祝好运! (我也对libgdx和clojure感兴趣)

let想尝试创建一个应用程序实例之前加载的资产。 libGDX模仿了android应用程序的生命周期,因此您不应在调用create之前尝试加载资产。

由于libGDX是Java框架,我们不能期望它与Clojure的纯功能方法相匹配。 某处必须有某种状态。 您可能想看看AssetManager

如果有人对Clojure有麻烦,并且示例游戏到这里结束了(就像我所做的那样),这是一个可行的实现的链接(尽管没有音乐/声音):

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

我仍然还只是开始学习Clojure,所以如果实现中的某些事情做得不好,请在评论中告诉我。

暂无
暂无

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

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