2012-03-22 16 views
8

से उछाल वाली वस्तुओं की कक्षा की जानकारी को बनाए रखना ठीक है, एक ऐसा कीवर्ड है जिसे मैंने जानबूझकर टैग और शीर्षक से दूर रखा है। यह "एंड्रॉइड" है, लेकिन ऐसा इसलिए है क्योंकि परियोजना एंड्रॉइड में है, लेकिन मुझे नहीं लगता कि मेरे प्रश्न के साथ कुछ भी करने के लिए कुछ भी नहीं है, और मैं एंड्रॉइड में अनुभव के बिना लोगों को डराना नहीं चाहता।एसआईजीआईजी जावा सी ++

तो, स्विग के साथ सामान्य समस्या। मेरे पास एक सी ++ कक्षा में वर्चुअल विधि है, जिसे मैंने कक्षा में director सुविधा जोड़कर जावा में अधिभारित किया है और यह काम करता है। समस्या यह है कि विधि को एक पॉलिमॉर्फिक तर्क प्राप्त होता है जिसे जावा पक्ष पर भी बढ़ाया जाता है, और जावा में आभासी विधि कॉल के दौरान, ऑब्जेक्ट सभी पॉलिमॉर्फिक सूचनाओं के साथ आता है।

सटीक स्थिति प्रस्तुत करने के लिए; मैं सी ++ में एक गेम इंजन लिख रहा हूं, और मैं इसे जावा में खुशी से उपयोग करना चाहता हूं। गेम इंजन में GameObject वर्ग है, जो CollisionListener एस पंजीकृत करता है और जब टकराव इंजन टकराव की घटना का पता लगाता है, तो यहसभी पंजीकृत collisionListener की विधि को उन ऑब्जेक्ट्स से गुजरता है जो उन्हें टकराते हैं।

class CollisionListener { 
public: 
    virtual bool collidedWith(GameObject &){}; 
    ~CollisionListener(){} // I know this needs to be virtual but let's forget about that now 
}; 

मैं जावा के लिए इस वर्ग को उजागर कर रहा हूँ, GameObject वर्ग के साथ निम्न इंटरफ़ेस फ़ाइल Bridge.i

%module(directors="1") Bridge 

%feature("director") CollisionListener; 
%include "CollisionListener"; 
%feature("director") GameObject; 
%include "GameObject.h" 

अब का उपयोग कर, जब मैं जावा और अधिभार collidedWith में CollisionListener से विरासत है, यह कहा जाता है के मिल जावा पक्ष GameObject ऑब्जेक्ट के साथ। उदाहरण के लिए, यदि मैं जावा पक्ष GameObject कक्षा से उत्तराधिकारी हूं और Bullet कक्षा को परिभाषित करता हूं, जब यह बुलेट श्रोता के साथ किसी अन्य ऑब्जेक्ट के साथ टकराता है, collidedWith विधि कॉल में, मुझे प्राप्त होता है यह एक नंगे GameObject है, ताकि (object instanceof Bullet) काम न करे। कोई आश्चर्य की बात है, मैं बड़ा घूँट में खोदे गए हैं BridgeJNI.java उत्पन्न होते हैं और यह पाया:

public static boolean SwigDirector_CollisionListener_collidedWith(CollisionListener self, long arg0) { 
    return self.collidedWith(new GameObject(arg0, false)); 
    } 

तो यह जावा भार के कॉल करने से पहले सूचक के चारों ओर एक नई वस्तु गिर्द घूमती है।

तो, मुख्य प्रश्न यह है कि टकराव होने पर Bullet ऑब्जेक्ट कैसे प्राप्त करें?

मैं आसानी से इसे प्राप्त करने के लिए एक रास्ता लेकर आया हूं, लेकिन मुझे ऑटो-जेनरेट की गई फ़ाइलों को संशोधित करने की आवश्यकता है, जो एक बुरा विचार है। तो मुझे उम्मीद है कि कुछ स्विग मास्टर मुझे स्विग जेनरेट की गई फ़ाइलों में संशोधन को इंजेक्ट करने में मदद कर सकता है।

मेरी छोटी हैक हर सी ++ पक्ष GameObject वस्तु में एक jobject * self रखने के लिए, और वास्तविक जावा पक्ष GameObject (और नहीं एक है कि केवल सूचक लपेटता) के निर्माण के दौरान वास्तविक जावा वस्तु का पता असाइन करने के लिए है। इस तरह, मैं सी ++ पक्ष GameObject में एक पॉलिमॉर्फिक getSelf विधि को परिभाषित कर सकता हूं और जावा में खुशी से परिणाम का उपयोग कर सकता हूं। क्या स्विग जेनरेट की गई फाइलों के लिए जरूरी कोड इंजेक्ट करने का कोई तरीका है?

धन्यवाद

नोट: यदि आप Android पर निर्देशकों की कोशिश की और वे काम नहीं किया है, तो ऐसा वर्तमान स्थिर संस्करण इसका समर्थन नहीं करता है। स्विग वेबसाइट से ब्लडिंग एज डाउनलोड करें। लेकिन मैं इसे 22/03/2012 में लिख रहा हूं और यह नोट जल्द ही अनावश्यक होगा। विनाशक वर्चुअल नहीं होने का कारण यह है कि रक्तस्राव एज संस्करण विनाशक में प्रोग्राम क्रैश करता है, और इसे गैर वर्चुअल बनाने के लिए इसे अभी नियंत्रण में रखना प्रतीत होता है।

+0

तो आपके प्रश्न का संक्षिप्त संस्करण यह है कि आप जावा में 'GameObject' प्राप्त करने में सक्षम होना चाहते हैं और फिर भी जावा के भीतर डालने में सक्षम होना चाहिए जब उस व्युत्पन्न प्रकार को' टक्कर के साथ 'जावा कार्यान्वयन में पारित किया जाता है? अगर यह मामला है तो निश्चित रूप से आपके छोटे हैक को टाइपमैप में लपेटा जा सकता है। – Flexo

+0

निश्चित रूप से! मैंने सोचा कि स्विग कोड को इंजेक्शन देने का एक तरीका होगा, लेकिन मैं स्विंग करने के लिए काफी नया हूं। मैं टाइपमैप की जांच करूंगा। – enobayram

+0

कल उम्मीद है कि मैं कल एक उत्तर लिखूंगा। – Flexo

उत्तर

8

मैंने इस समस्या का समाधान एक साथ रखा है। यह आपके प्रश्न में सुझाए गए समाधान का काफी समाधान नहीं है, हालांकि यह जावा पक्ष पर अधिक कोड है और जेएनआई/सी ++ पक्ष पर कोई अतिरिक्त नहीं है। (मैंने यह पाया कि जिस तरह से आपने सभी संभावित मामलों में सही होने के लिए काफी मुश्किल सुझाव दिया है)।

मैं एक ही हेडर फाइल करने के लिए नीचे अपनी कक्षाओं को सरल बनाया:

class GameObject { 
}; 

class CollisionListener { 
public: 
    virtual bool collidedWith(GameObject &) { return false; } 
    virtual ~CollisionListener() {} 
}; 

inline void makeCall(GameObject& o, CollisionListener& c) { 
    c.collidedWith(o); 
} 

जो भी makeCall जोड़ा वास्तव में समस्या स्पष्ट बनाने के लिए।

मैं जिस चाल का उपयोग करता हूं वह GameObject के सभी जावा व्युत्पन्न उदाहरणों को HashMap में स्वचालित रूप से निर्माण समय पर पंजीकृत करना है। फिर निदेशक कॉल को प्रेषित करते समय यह हैश मैप में इसे देखने का एक सवाल है।

फिर मॉड्यूल फ़ाइल:

%module(directors="1") Test 

%{ 
#include "test.hh" 
%} 

%pragma(java) jniclasscode=%{ 
    static { 
    try { 
     System.loadLibrary("test"); 
    } catch (UnsatisfiedLinkError e) { 
     System.err.println("Native code library failed to load. \n" + e); 
     System.exit(1); 
    } 
    } 
%} 

/* Pretty standard so far, loading the shared object 
    automatically, enabling directors and giving the module a name. */  

// An import for the hashmap type 
%typemap(javaimports) GameObject %{ 
import java.util.HashMap; 
import java.lang.ref.WeakReference; 
%} 

// Provide a static hashmap, 
// replace the constructor to add to it for derived Java types 
%typemap(javabody) GameObject %{ 
    private static HashMap<Long, WeakReference<$javaclassname>> instances 
         = new HashMap<Long, WeakReference<$javaclassname>>(); 

    private long swigCPtr; 
    protected boolean swigCMemOwn; 

    public $javaclassname(long cPtr, boolean cMemoryOwn) { 
    swigCMemOwn = cMemoryOwn; 
    swigCPtr = cPtr; 
    // If derived add it. 
    if (getClass() != $javaclassname.class) { 
     instances.put(swigCPtr, new WeakReference<$javaclassname>(this)); 
    } 
    } 

    // Just the default one 
    public static long getCPtr($javaclassname obj) { 
    return (obj == null) ? 0 : obj.swigCPtr; 
    } 

    // Helper function that looks up given a pointer and 
    // either creates or returns it 
    static $javaclassname createOrLookup(long arg) { 
    if (instances.containsKey(arg)) { 
     return instances.get(arg).get(); 
    } 
    return new $javaclassname(arg,false); 
    } 
%} 

// Remove from the map when we release the C++ memory 
%typemap(javadestruct, methodname="delete", 
     methodmodifiers="public synchronized") GameObject { 
    if (swigCPtr != 0) { 
    // Unregister instance 
    instances.remove(swigCPtr); 
    if (swigCMemOwn) { 
     swigCMemOwn = false; 
     $imclassname.delete_GameObject(swigCPtr); 
    } 
    swigCPtr = 0; 
    } 
} 

// Tell SWIG to use the createOrLookup function in director calls. 
%typemap(javadirectorin) GameObject& %{ 
    $javaclassname.createOrLookup($jniinput) 
%} 
%feature("director") GameObject; 

// Finally enable director for CollisionListener and include the header 
%feature("director") CollisionListener;  
%include "test.hh" 

ध्यान दें कि के बाद से सभी जावा उदाहरणों एक HashMap में संग्रहित किया जा रहा है हम एक WeakReference उपयोग करने के लिए सुनिश्चित करें कि हम उनके जीवन के समय को बढ़ाने नहीं कर रहे हैं और से कचरा संग्रहण को रोकने की जरूरत है हो रहा। यदि आप धागे की परवाह करते हैं तो सिंक्रनाइज़ेशन को उचित के रूप में जोड़ें।

मैं के साथ इस परीक्षण किया:

public class main { 
    public static void main(String[] argv) { 
    JCollisionListener c = new JCollisionListener(); 
    JGameObject o = new JGameObject(); 
    c.collidedWith(o); 
    Test.makeCall(o,c); 
    } 
} 

JCollisionListener कहां है:

public class JCollisionListener extends CollisionListener { 
    public boolean collidedWith(GameObject i) { 
    System.out.println("In collide"); 
    if (i instanceof JGameObject) { 
     System.out.println("Is J"); 
    } 
    else { 
     System.out.println("Not j"); 
    } 
    JGameObject o = (JGameObject)i; 
    return false; 
    } 
} 

और JGameObject है:

public class JGameObject extends GameObject { 
} 

(संदर्भ के लिए यदि आप अन्य दृष्टिकोण आप करना चाहते थे directorin टाइपमैप लिखने पर विचार करेगा)।

+0

वाह! इतना प्रयास और एक महान जवाब। ऐसा लगता है कि मेरी समस्या हल हो रही है, साथ ही मुझे स्विग के बारे में बहुत कुछ सिखा रहा है। ऐसा लगता है कि हमें कभी-कभी आधा स्विंग को ओवरराइड करने की आवश्यकता होती है ताकि हम जो चाहते हैं उसे प्राप्त कर सकें। बहुत बहुत धन्यवाद। – enobayram

+0

एसडब्ल्यूआईजी के बारे में अच्छी बात यह है कि यह आपको इस तरह की चीजों को करने की इजाजत देता है, लेकिन यह सब कुछ encapsulates ताकि आपको केवल "विषम" बिट्स पर काम करना पड़े और सभी गंदे काम आपके लिए किया जाता है। – Flexo

+0

सॉफ़्टवेयर इंजीनियरों का कभी भी अंतिम निर्णय लेने का निर्णय नहीं: "मुझे अपना समय कहां निवेश करना चाहिए?"। एसडब्ल्यूआईजी एक अच्छा सौदा प्रतीत होता है क्योंकि क्रॉस-भाषा की समस्या के दृष्टिकोण के रूप में यह सामान्य होता है। मेरा मतलब है, बाहरी कोड जेनरेटर के रूप में, यह सबसे अधिक सीमाओं से मुक्त है जो पूरी तरह लाइब्रेरी आधारित समाधान (जैसे बूस्ट पायथन) पीड़ित हैं। – enobayram