أفضل طريقة لتعزيز أداء لعبة LWJGL الخاصة بي؟
-
10-12-2019 - |
سؤال
أقوم بتجميع مشروع صغير للمدرسة يتضمن عرض الجدول الدوري.لقد اخترت استخدام LWJGL للقيام بذلك.ومع ذلك، تكمن المشكلة في أنه عندما أقوم بعرض الجدول، تبدأ اللعبة بمعدل 30 إطارًا في الثانية تقريبًا (بحد أقصى 60 إطارًا في الثانية)، وتتقلب بسرعة إلى معدل إطار واحد في الثانية.أعتقد أن المشكلة قد تكون تسربًا للذاكرة، لكنني غير متأكد.هل يمكن لأي شخص رؤية أي مشاكل صارخة في الكود الخاص بي؟فيما يلي الفئات الرئيسية المشاركة في عرض الجدول:
الجدول الدوري للكيان:مسؤول عن الاحتفاظ بمجموعة كبيرة من كائنات EntityElement (انظر أدناه)، وتنشيط منطقها (tick() وupdateInput()).package com.flafla2.periodicTable;
import org.lwjgl.opengl.GL11;
public class EntityPeriodicTable extends ClickableEntity { //ClickableEntity is an abstract class in charge of the tick(), updateInput(), and render() methods, as well as positioning
public EntityElement[] elements = {//This is unfinished, but you get the idea.
//new EntityElement(Atomic #, State, Metal, "Symbol", "Name", new Vector2D(posx,posy), this)
new EntityElement(1, 2, 2, "H", "Hydrogen", new Vector2D(1,1), this),
new EntityElement(2, 2, 2, "He", "Helium", new Vector2D(18,1), this),
new EntityElement(3, 0, 0, "Li", "Lithium", new Vector2D(1,2), this),
new EntityElement(4, 0, 0, "Be", "Beryllium", new Vector2D(2,2), this),
new EntityElement(5, 0, 1, "B", "Boron", new Vector2D(13,2), this),
new EntityElement(6, 0, 2, "C", "Carbon", new Vector2D(14,2), this),
new EntityElement(7, 2, 2, "N", "Nitrogen", new Vector2D(15,2), this),
new EntityElement(8, 2, 2, "O", "Oxygen", new Vector2D(16,2), this),
new EntityElement(9, 2, 2, "F", "Fluorine", new Vector2D(17,2), this),
new EntityElement(10,2, 2, "Ne", "Neon", new Vector2D(18,2), this),
new EntityElement(11, 0, 0, "Na", "Sodium", new Vector2D(1,3), this),
new EntityElement(12, 0, 0, "Mg", "Magnesium", new Vector2D(2,3), this),
new EntityElement(13, 0, 0, "Al", "Aluminum", new Vector2D(13,3), this),
new EntityElement(14, 0, 1, "Si", "Silicon", new Vector2D(14,3), this),
new EntityElement(15, 0, 2, "P", "Phosphorous", new Vector2D(15,3), this),
new EntityElement(16, 0, 2, "S", "Sulfur", new Vector2D(16,3), this),
new EntityElement(17, 2, 2, "Cl", "Chlorine", new Vector2D(17,3), this),
new EntityElement(18, 2, 2, "Ar", "Argon", new Vector2D(18,3), this),
new EntityElement(19, 0, 0, "K", "Potassium", new Vector2D(1,4), this),
new EntityElement(20, 0, 0, "Ca", "Calcium", new Vector2D(2,4), this),
new EntityElement(21, 0, 0, "Sc", "Scandium", new Vector2D(3,4), this),
new EntityElement(22, 0, 0, "Ti", "Hydrogen", new Vector2D(4,4), this),
new EntityElement(23, 0, 0, "V", "Hydrogen", new Vector2D(5,4), this),
new EntityElement(24, 0, 0, "Cr", "Hydrogen", new Vector2D(6,4), this),
new EntityElement(25, 0, 0, "Mn", "Hydrogen", new Vector2D(7,4), this),
new EntityElement(26, 0, 0, "Fe", "Hydrogen", new Vector2D(8,4), this),
new EntityElement(27, 0, 0, "Co", "Hydrogen", new Vector2D(9,4), this),
new EntityElement(28, 0, 0, "Ni", "Hydrogen", new Vector2D(10,4), this),
new EntityElement(29, 0, 0, "Cu", "Hydrogen", new Vector2D(11,4), this),
new EntityElement(30, 0, 0, "Zn", "Hydrogen", new Vector2D(12,4), this),
new EntityElement(31, 0, 0, "Ga", "Hydrogen", new Vector2D(13,4), this),
new EntityElement(32, 0, 1, "Ge", "Hydrogen", new Vector2D(14,4), this),
new EntityElement(33, 0, 1, "As", "Hydrogen", new Vector2D(15,4), this),
new EntityElement(34, 0, 2, "Se", "Hydrogen", new Vector2D(16,4), this),
new EntityElement(35, 1, 2, "Br", "Hydrogen", new Vector2D(17,4), this),
new EntityElement(36, 2, 2, "Kr", "Hydrogen", new Vector2D(18,4), this),
};
public final int ELEMENT_SIZE = 40;
public Vector2D mousePos = new Vector2D(0,0); //Simple 2D vector struct.
public double[] SOLID_RGB = {0,0,0};
public double[] LIQUID_RGB = {0,0,1};
public double[] GAS_RGB = {1,0,0};
public double[] METAL_RGB;
public double[] NONMETAL_RGB;
public double[] METALLOID_RGB;
public double[] RECENT_RGB;
public EntityPeriodicTable(Vector2D pos) {
this.pos = pos;
METAL_RGB = new double[3];
METAL_RGB[0] = 0.596078431; //152/255
METAL_RGB[1] = 0.984313725; //251/255
METAL_RGB[2] = 0.596078431; //152/255
NONMETAL_RGB = new double[3];
NONMETAL_RGB[0] = 1;
NONMETAL_RGB[1] = 0.647058824; //165/255
NONMETAL_RGB[2] = 0;
METALLOID_RGB = new double[3];
METALLOID_RGB[0] = 0.866666667; //221/255
METALLOID_RGB[1] = 0.62745098; //160/255
METALLOID_RGB[2] = 0.866666667; //221/255
RECENT_RGB = new double[3];
RECENT_RGB[0] = 0.803921569; //205/255
RECENT_RGB[1] = 0.788235294; //201/255
RECENT_RGB[2] = 0.788235294; //201/255
}
@Override
void render() {
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_BLEND);
for(int x=0;x<elements.length;x++)
elements[x].render();
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glEnable(GL11.GL_BLEND);
for(int x=0;x<elements.length;x++)
elements[x].renderWithTex();
}
@Override
void tick() {
for(int x=0;x<elements.length;x++)
elements[x].tick();
}
@Override
public void updateInput(Vector2D mousePos)
{
this.mousePos = mousePos;
for(int x=0;x<elements.length;x++)
{
if(mousePos.isInBoundsWithDim(elements[x].pos.x, elements[x].pos.y, elements[x].dim.x, elements[x].dim.y))
elements[x].isSelected = true;
else
elements[x].isSelected = false;
}
}
@Override
void onEntityClicked() {
for(int x=0;x<elements.length;x++)
{
if(mousePos.isInBoundsWithDim(elements[x].pos.x, elements[x].pos.y, elements[x].dim.x, elements[x].dim.y))
elements[x].onEntityClicked();
}
}
}
عنصر الكيان:يحتفظ ببيانات عنصر معين في الجدول ويعرضها (رمز العرض غير مكتمل)
package com.flafla2.periodicTable;
import org.lwjgl.opengl.GL11;
public class EntityElement extends ClickableEntity {
String symbol;
String element;
int atomicNumber;
EntityPeriodicTable table;
int state;//0=solid, 1=liquid, 2=gas
int metalState;//0=metal, 1=metalloid, 2=nonmetal, 3=discovered recently
Vector2D gridPos;
public EntityElement(int an, int st, int ms, String sy, String en, Vector2D gp, EntityPeriodicTable pt)
{
symbol = sy;
element = en;
atomicNumber = an;
table = pt;
state = st;
metalState = ms;
gridPos = gp;
dim.x = table.ELEMENT_SIZE; dim.y = table.ELEMENT_SIZE;
pos.x = table.pos.x + table.ELEMENT_SIZE*(gridPos.x-1); pos.y = table.pos.y + table.ELEMENT_SIZE*(gridPos.y-1);
}
public double[] getStateColor()
{
switch(state)
{
case 0:
return table.SOLID_RGB;
case 1:
return table.LIQUID_RGB;
case 2:
return table.GAS_RGB;
default:
double[] d = {0.0d,0.0d,0.0d};
return d;
}
}
public double[] getMetalColor()
{
switch(metalState)
{
case 0:
return table.METAL_RGB;
case 1:
return table.METALLOID_RGB;
case 2:
return table.NONMETAL_RGB;
case 3:
return table.RECENT_RGB;
default:
double[] d = {0.0d,0.0d,0.0d};
return d;
}
}
@Override
void render() {
GL11.glPushMatrix();
GL11.glTranslatef(pos.x, pos.y, 0);
double[] d = getMetalColor();
GL11.glColor3d(d[0], d[1], d[2]);
GL11.glBegin(GL11.GL_QUADS);
{
GL11.glVertex2f(0, 0);//topleft
GL11.glVertex2f(dim.x, 0);//topright
GL11.glVertex2f(dim.x, dim.y);//bottomright
GL11.glVertex2f(0, dim.y);//bottomleft
}
GL11.glEnd();
GL11.glColor3d(1.0d, 1.0d, 1.0d);
GL11.glPopMatrix();
}
public void renderWithTex()
{
Font.drawString(symbol, new Vector2D(pos.x+dim.x/2-Font.getStringWidth(symbol,2)/2,pos.y+dim.y/2-Font.FONT_HEIGHT), 2);
}
@Override
void tick() {
if(isSelected)
{
dim.x = table.ELEMENT_SIZE+6; dim.y = table.ELEMENT_SIZE+6;
pos.x = table.pos.x + table.ELEMENT_SIZE*(gridPos.x-1)-3; pos.y = table.pos.y + table.ELEMENT_SIZE*(gridPos.y-1)-3;
} else
{
dim.x = table.ELEMENT_SIZE; dim.y = table.ELEMENT_SIZE;
pos.x = table.pos.x + table.ELEMENT_SIZE*(gridPos.x-1); pos.y = table.pos.y + table.ELEMENT_SIZE*(gridPos.y-1);
}
}
@Override
void onEntityClicked() {
}
}
الخط:يعالج عرض النص على الشاشة:
package com.flafla2.periodicTable;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import org.lwjgl.opengl.GL11;
public class Font {
public static final String fontText = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789:;?!\"&',-.[]#()+ ";
public static final BufferedImage fontSheet = TextureLoader.loadTexture("/res/text.png");
public static final int FONT_WIDTH = 9;
public static final int FONT_HEIGHT = 8;
public static void drawString(String s, Vector2D pos, float dim)
{
drawString(s,pos,new Vector2D((int)Math.floor(dim*FONT_WIDTH),(int)Math.floor(dim*FONT_HEIGHT)));
}
public static void drawString(String s, Vector2D pos)
{
drawString(s,pos,new Vector2D(9,8));
}
public static void drawString(String s, Vector2D pos, Vector2D dim)
{
for(int x=0;x<s.length();x++)
{
drawLetter(s.charAt(x),new Vector2D(pos.x+dim.x*x,pos.y),dim);
}
}
public static int getStringWidth(String s)
{
return s.length()*FONT_WIDTH;
}
public static int getStringWidth(String s,float f)
{
return (int)Math.floor(s.length()*FONT_WIDTH*f);
}
public static Vector2D getPosOfLetterOnImg(Character c,int gridNumb)
{
int xOffset = 0;
int yOffset = 0;
if(!c.equals(' '))
{
int letterNumb = fontText.indexOf(c);
xOffset = (letterNumb%26)*FONT_WIDTH;
if(xOffset != 0)
xOffset -=1;
yOffset = 0;
int yGridOffset = (letterNumb < 26) ? 0 : ((letterNumb < 52) ? 1 : 2);
switch(gridNumb)
{
case 1:
yOffset = 34;
break;
case 2:
yOffset = 69;
break;
default:
yOffset = 0;
}
for(int x=0;x<yGridOffset;x++)
yOffset += FONT_HEIGHT+x+3;
} else
{
xOffset = 235;
yOffset = 92;
}
return new Vector2D(xOffset,yOffset);
}
public static void drawLetter(Character c, Vector2D pos, Vector2D dim)
{
if(fontSheet == null)
return;
Vector2D letterPos = getPosOfLetterOnImg(c,2);
BufferedImage letterImage = fontSheet.getSubimage(letterPos.x, letterPos.y, FONT_WIDTH, FONT_HEIGHT);
int textureID = TextureLoader.loadGLTexture(letterImage);
letterImage = null;
GL11.glPushMatrix();
GL11.glTranslatef(pos.x, pos.y, 0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL11.glBegin(GL11.GL_QUADS);
{
GL11.glTexCoord2f(0, 0);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2f(1, 0);
GL11.glVertex2f(dim.x, 0);
GL11.glTexCoord2f(1, 1);
GL11.glVertex2f(dim.x, dim.y);
GL11.glTexCoord2f(0, 1);
GL11.glVertex2f(0, dim.y);
}
GL11.glEnd();
GL11.glPopMatrix();
}
}
محمل الملمس:الأحمال القوام (دوه لول)
package com.flafla2.periodicTable;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
public class TextureLoader {
public static BufferedImage loadTexture(String texturePath)
{
try {
return ImageIO.read(PeriodicTable.class.getResource(texturePath));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
private static final int BYTES_PER_PIXEL = 4;
public static int loadGLTexture(BufferedImage image){
int[] pixels = new int[image.getWidth() * image.getHeight()];
image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * BYTES_PER_PIXEL); //4 for RGBA, 3 for RGB
for(int y = 0; y < image.getHeight(); y++){
for(int x = 0; x < image.getWidth(); x++){
int pixel = pixels[y * image.getWidth() + x];
buffer.put((byte) ((pixel >> 16) & 0xFF)); // Red component
buffer.put((byte) ((pixel >> 8) & 0xFF)); // Green component
buffer.put((byte) (pixel & 0xFF)); // Blue component
buffer.put((byte) ((pixel >> 24) & 0xFF)); // Alpha component. Only for RGBA
}
}
buffer.flip(); //FOR THE LOVE OF GOD DO NOT FORGET THIS
// You now have a ByteBuffer filled with the color data of each pixel.
// Now just create a texture ID and bind it. Then you can load it using
// whatever OpenGL method you want, for example:
int textureID = GL11.glGenTextures(); //Generate texture ID
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID); //Bind texture ID
//Setup wrap mode
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
//Setup texture scaling filtering
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
//Send texel data to OpenGL
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
buffer = null;
//Return the texture ID so we can bind it later again
return textureID;
}
}
أعلم أن هناك الكثير من التعليمات البرمجية، ولكن إذا كان بإمكان أي شخص مساعدتي فسيكون موضع تقدير كبير.
شكرا فلافلا2.
المحلول 2
حسنًا، لقد وجدت المشكلة.
في TextureLoader.java
, ، لم أستخدم glDeleteTextures(textureID)
, ، وبالتالي فإن القوام المستخدم في Font.java
لم يتم تفريغها من الذاكرةالآن، أحصل على معدل ثابت يزيد عن 50 إطارًا في الثانية (على جهاز Macbook السيئ الخاص بي بالطبع).
أيضًا ، أدت الإجابة المحددة الأخرى إلى زيادة عدد الإطارات في الثانية إلى 60 تقريبًا.وفي حال كان أي شخص يتساءل، هنا هو الجديد drawLetter()
الطريقة مع التغييرات:
public static void drawLetter(Character c, Vector2D pos, Vector2D dim)
{
if(fontSheet == null)
return;
Vector2D letterPos = getPosOfLetterOnImg(c,2);
//BufferedImage letterImage = fontSheet.getSubimage(letterPos.x, letterPos.y, FONT_WIDTH, FONT_HEIGHT);
//int textureID = TextureLoader.loadGLTexture(letterImage);
//letterImage = null;
int width = fontSheet.getWidth(); int height = fontSheet.getHeight();
double d[] = {(double)letterPos.x/width, (double)letterPos.y/height, (double)(letterPos.x+FONT_WIDTH)/width, (double)(letterPos.y+FONT_HEIGHT)/height};
GL11.glPushMatrix();
GL11.glTranslatef(pos.x, pos.y, 0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
GL11.glBegin(GL11.GL_QUADS);
{
GL11.glTexCoord2d(d[0], d[1]);
GL11.glVertex2f(0, 0);
GL11.glTexCoord2d(d[2], d[1]);
GL11.glVertex2f(dim.x, 0);
GL11.glTexCoord2d(d[2], d[3]);
GL11.glVertex2f(dim.x, dim.y);
GL11.glTexCoord2d(d[0], d[3]);
GL11.glVertex2f(0, dim.y);
}
GL11.glEnd();
GL11.glPopMatrix();
//GL11.glDeleteTextures(textureID);
}
نصائح أخرى
اعتقدت أنك حل allready هل هناك مجال أكثر للتحسين.أرى أن لديك الخط الخاص بك في صورة ولكل حرف تريد سحبه لك الحصول على جزء من الصورة مع تحميل هذه الرسالة في نسيج وبعد ذلك يجب تنظيف كل ما يجب تنظيفه.
أفضل لتحميل الصورة بأكملها في نسيج كبير واحد، والحفاظ على هذا الملمس طوال مدة البرنامج وإعادة استخدامه عند تقديم كل إطار.يمكنك تحديد الأحرف الصحيحة في التجسيد عن طريق تحديد إحداثيات الملمس الصحيحة.
يجب أن تكون قادرا على ضرب غطاء 60 إطارا في الثانية باستخدام استخدام وحدة المعالجة المركزية المنخفضة ما لم يكن MacBook قديم حقا.