سؤال

أقوم حاليا بتطوير لعبة OpenGL صغيرة منصة Android وأتساءل عما إذا كانت هناك طريقة سهلة لتقديم النص الموجود أعلى الإطار المنصوص عليه (مثل HUD مع النتيجة للاعب وغيرها). يحتاج النص إلى استخدام خط مخصص أيضا.

لقد رأيت مثالا باستخدام عرض كتراكب، لكنني لا أعرف إذا كنت أريد أن أفعل ذلك لأنني قد أرغب في نقل اللعبة إلى منصات أخرى لاحقا.

أيه أفكار؟

هل كانت مفيدة؟

المحلول

لا يأتي Android SDK بأي طريقة سهلة لرسم النص على طرق عرض OpenGL. تركك مع الخيارات التالية.

  1. ضع نصوص نصية على سطح المكتب الخاص بك. هذا بطيء وسوء، ولكن النهج الأكثر مباشرة.
  2. جعل سلاسل مشتركة للقوام، وببساطة رسم تلك القوام. هذا إلى حد بعيد أبسط وأسرع، ولكن الأقل مرونة.
  3. لف رمز تقديم النصوص الخاصة بك على أساس العفريت. ربما ثانيا أفضل خيار إذا كان 2 ليس خيارا. طريقة جيدة للحصول على قدميك الرطب ولكن لاحظ أنه على الرغم من أنه يبدو بسيطا (وميزات أساسية)، فإنه يصعب أكثر صعوبة وأكثر صعوبة أثناء إضافة المزيد من الميزات (محاذاة الملمس، التعامل مع فواصل الأسطر وخطوط العرض المتغير إلخ. ) - إذا كنت تأخذ هذا الطريق، اجعله بسيطا كما يمكنك الابتعاد عن!
  4. استخدم مكتبة خارجية / مفتوحة المصدر. هناك عدد قليل من حولك إذا كنت تطارد على Google، فإن الشيء الصعب هو الحصول على دمجها وتشغيلها. ولكن على الأقل، بمجرد أن تفعل ذلك، سيكون لديك كل المرونة والنضج الذي يقدمونه.

نصائح أخرى

يعد تقديم النص إلى نسيج بملمس أكثر بساطة مما يجعله توضيح نص Sprite، والفكرة الأساسية هي استخدام فئة Canvas لتعدد صورة نقطية ثم قم بتمرير الصورة النقطية إلى نسيج OpenGL:

// Create an empty, mutable bitmap
Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_4444);
// get a canvas to paint over the bitmap
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);

// get a background image from resources
// note the image format must match the bitmap format
Drawable background = context.getResources().getDrawable(R.drawable.background);
background.setBounds(0, 0, 256, 256);
background.draw(canvas); // draw the background to our bitmap

// Draw the text
Paint textPaint = new Paint();
textPaint.setTextSize(32);
textPaint.setAntiAlias(true);
textPaint.setARGB(0xff, 0x00, 0x00, 0x00);
// draw the text centered
canvas.drawText("Hello World", 16,112, textPaint);

//Generate one texture pointer...
gl.glGenTextures(1, textures, 0);
//...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

//Create Nearest Filtered Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

//Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);

//Use the Android GLUtils to specify a two-dimensional texture image from our bitmap
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

//Clean up
bitmap.recycle();

لقد كتبت أ درس تعليمي التي تتوسع على الإجابة المنشورة جفيتيلا. وبعد في الأساس، يستخدم الفكرة نفسها، ولكن بدلا من تقديم كل سلسلة إلى نسيج، فإنه يجعل جميع الأحرف من ملف الخط إلى نسيج ويستخدم ذلك للسماح بتقديم نص ديناميكي كامل مع عدم تباطؤ إضافي (بمجرد اكتمال التهيئة) وبعد

الميزة الرئيسية لطريقتي، مقارنة بمولدات خطوط أطلس الخط المختلفة، هي أنه يمكنك شحن ملفات الخطوط الصغيرة (.ttf .otf) مع مشروعك بدلا من الاضطرار إلى شحن الصور النقطية الكبيرة لكل تغيير الخط وحجمها. يمكن أن تولد خطوط ذات جودة مثالية عند أي دقة باستخدام ملف الخط فقط :)

ال درس تعليمي يتضمن الكود الكامل الذي يمكن استخدامه في أي مشروع :)

وفقا لهذا الرابط:

http://code.neenbedankt.com/how-to-render-an-android-view-to-bitmap.

يمكنك تقديم أي رأي إلى صورة نقطية. ربما يستحق افتراض أنه يمكنك تخطيط عرض كما تحتاج (بما في ذلك النص والصور وما إلى ذلك) ثم أعدها إلى صورة نقطية.

باستخدام رمز Jvitela في الاعلى يجب أن تكون قادرا على استخدام هذه الصورة النقطية كملمس OpenGL.

إلقاء نظرة على CBFG ومنفذ Android من رمز التحميل / تقديم. يجب أن تكون قادرا على إسقاط التعليمات البرمجية في مشروعك واستخدامها على الفور.

CBFG - http://www.codehead.co.uk/cbfg.

Android Loader - http://www.codehead.co.uk/cbfg/texfont.java.

نظرت إلى مثال نص العفريت وأنها تبدو معقدة بفظاعة لمثل هذه المهمة، فكرت في التقديم إلى نسيج أيضا، لكنني قلقة من ضرب الأداء الذي قد يسبب ذلك. قد تضطر فقط إلى الذهاب مع عرض بدلا من ذلك والقلق بشأن التنقل عندما حان الوقت لعبور هذا الجسر :)

إلقاء نظرة على عينة "نص العفريت" في عينات glsurfaceview..

IMHO هناك ثلاثة أسباب لاستخدام OpenGL ES في لعبة:

  1. تجنب الاختلافات بين المنصات المتنقلة باستخدام معيار مفتوح؛
  2. للحصول على المزيد من السيطرة على عملية التجسيد؛
  3. للاستفادة من المعالجة المتوازية GPU؛

نص الرسم هو دائما مشكلة في تصميم اللعبة، لأنك ترسم الأشياء، لذلك لا يمكن أن يكون لديك نظرة وشعور بنشاط مشترك، مع الحاجيات وهلم جرا.

يمكنك استخدام إطار لإنشاء خطوط NETMAP من خطوط تروتايب وتقديمها. تعمل جميع الأطر التي رأيتها بنفس الطريقة: إنشاء إحداثيات Vertex والملمس للنص في وقت التصوير. هذا ليس استخدام OpenGL الأكثر فعالية.

أفضل طريقة هي تخصيص المخازن المؤقتة عن بعد (كائنات المخزن المؤقت VERTEX - VBOS) للقمم والقوام في وقت مبكر من التعليمات البرمجية، وتجنب عمليات نقل الذاكرة الكسولة في وقت التصوير.

ضع في اعتبارك أن لاعبي اللعبة لا يحبون قراءة النص، لذلك لن تكتب نصا طويلا تم إنشاؤه ديناميكيا. بالنسبة للملصقات، يمكنك استخدام القوام الثابتة، وترك النص الديناميكي للوقت والنتيجة، وكلاهما رقم رقمي مع عدد قليل من الأحرف.

لذلك، الحل الخاص بي بسيط:

  1. إنشاء نسيج للملصقات الشائعة والتحذيرات؛
  2. قم بإنشاء نسيج للأرقام 0-9، ":": "،" + "، و" - ". نسيج واحد لكل حرف؛
  3. إنشاء VBOS عن بعد لجميع الوظائف في الشاشة. يمكنني تقديم نص ثابت أو ديناميكي في تلك المراكز، لكن VBOs ثابتة؛
  4. توليد واحدة فقط من نسيج واحد، كما يتم تقديم نص دائما بطريقة واحدة؛
  5. في وقت التصوير، أقدم النص الثابت؛
  6. بالنسبة للنص الديناميكي، يمكنني الحصول على نظرة خاطفة على موقف VBO، واحصل على نسيج الحرف واسحبه، شخصية في وقت واحد.

عمليات السحب سريعة، إذا كنت تستخدم المخازن المؤقتة الثابتة عن بعد.

أقوم بإنشاء ملف XML مع مواقع الشاشة (استنادا إلى النسبة المئوية القطرية في الشاشة) والقوام (ثابتة وأحرف)، ثم قمت بتحميل XML هذا قبل التقديم.

للحصول على معدل FPS مرتفع، يجب تجنب توليد VBOS في وقت الرسم.

إذا أصرت على استخدام GL، فيمكنك تقديم النص إلى القوام. على افتراض أن معظم HUD ثابت نسبيا، يجب ألا تضطر إلى تحميل القوام إلى ذاكرة الملمس في كثير من الأحيان.

إلقاء نظرة على CBFG وينفذ Android من رمز التحميل / تقديم. يجب أن تكون قادرا على إسقاط التعليمات البرمجية في مشروعك واستخدامها على الفور.

  1. CBFG.

  2. تحميل الروبوت

لدي مشاكل في هذا التنفيذ. إنه يعرض حرفا واحدا فقط، عندما أحاول إجراء تغيير حجم الصورة النقطية للخط (أحتاج رسائل خاصة) فشل السحب الكامل :(

لقد كنت أبحث عن ذلك لبضع ساعات، وكانت هذه المادة الأولى التي أتيت فيها، وعلى الرغم من أنها لديها أفضل إجابة، فإن الإجابات الأكثر شعبية وأعتقد أنها خارج العلامة. بالتأكيد لما كنت بحاجة إليه. كانت إجابات Weichsel's و Shakazed على الفور على الزر، ولكنها تحجب بعض الشيء في المقالات. لوضع لك الحق في المشروع. هنا: فقط إنشاء مشروع Android جديد يعتمد على العينة الموجودة. اختر Apidemos:

انظر تحت المجلد المصدر

ApiDemos/src/com/example/android/apis/graphics/spritetext

وسوف تجد كل ما تحتاجه.

ل نص ثابت:

  • توليد صورة بها كل الكلمات المستخدمة على جهاز الكمبيوتر الخاص بك (على سبيل المثال مع GIMP).
  • قم بتحميل هذا كملمس واستخدامه كمواد لطائرة.

ل نص طويل يجب أن يتم تحديثها مرة واحدة في حين:

  • دع Android تعادل على قماش نقطية (حل Jvitela).
  • تحميل هذا كمواد لطائرة.
  • استخدم إحداثيات نسيج مختلفة لكل كلمة.

ل رقم (تنسيق 00.0):

  • توليد صورة بها جميع الأرقام وطريقة.
  • تحميل هذا كمواد لطائرة.
  • استخدام أدناه شاد.
  • في حدث OnDraw الخاص بك فقط تحديث متغير القيمة المرسل إلى Shader.

    precision highp float;
    precision highp sampler2D;
    
    uniform float uTime;
    uniform float uValue;
    uniform vec3 iResolution;
    
    varying vec4 v_Color;
    varying vec2 vTextureCoord;
    uniform sampler2D s_texture;
    
    void main() {
    
    vec4 fragColor = vec4(1.0, 0.5, 0.2, 0.5);
    vec2 uv = vTextureCoord;
    
    float devisor = 10.75;
    float digit;
    float i;
    float uCol;
    float uRow;
    
    if (uv.y < 0.45) {
        if (uv.x > 0.75) {
            digit = floor(uValue*10.0);
            digit = digit - floor(digit/10.0)*10.0;
            i = 48.0 - 32.0 + digit;
            uRow = floor(i / 10.0);
            uCol = i - 10.0 * uRow;
            fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-1.5) / devisor, uRow / devisor) );
        } else if (uv.x > 0.5) {
            uCol = 4.0;
            uRow = 1.0;
            fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-1.0) / devisor, uRow / devisor) );
        } else if (uv.x > 0.25) {
            digit = floor(uValue);
            digit = digit - floor(digit/10.0)*10.0;
            i = 48.0 - 32.0 + digit;
            uRow = floor(i / 10.0);
            uCol = i - 10.0 * uRow;
            fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-0.5) / devisor, uRow / devisor) );
        } else if (uValue >= 10.0) {
            digit = floor(uValue/10.0);
            digit = digit - floor(digit/10.0)*10.0;
            i = 48.0 - 32.0 + digit;
            uRow = floor(i / 10.0);
            uCol = i - 10.0 * uRow;
            fragColor = texture2D( s_texture, uv / devisor * 2.0 + vec2((uCol-0.0) / devisor, uRow / devisor) );
        } else {
            fragColor = vec4(0.0, 0.0, 0.0, 0.0);
        }
    } else {
        fragColor = vec4(0.0, 0.0, 0.0, 0.0);
    }
    gl_FragColor = fragColor;
    
    }
    

يعمل الرمز أعلاه لأطلس نسيج حيث تبدأ الأرقام من 0 في العمود السابع من الصف الثاني من أطلس الخط (الملمس).

تشير إلى https://www.shaderto.com/view/xl23dw. للتظاهر (مع نسيج خاطئ على الرغم من)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top