Performance Issues
by Alex Poli · in Torque 2D Beginner · 05/23/2013 (7:33 pm) · 8 replies
Hello, recently I have been working on implementing a simple, fake 3D effect in t2d which works by updating the position of sprites in relation to the player and an input height value. I have it all working, but when I add more than about three of these objects the game slows down considerably. This is probably due to my inexperience with this kind of programming and the engine, so I was hoping you guys might have some pointers on improving the efficiency of what I am trying to do. What I am thinking of doing now is implementing the math-heavy functions into the engine itself as C++ should be faster than torquescript. I wanted to run my implementation by you guys first though because it might just be slow because I am doing it stupidly.
Below is my code for cuboid and cylinder objects as well as the update functions. I think the problem is with how I am performing the updates to the objects.
Cuboid:
Cylinder:
Update functions:
Below is my code for cuboid and cylinder objects as well as the update functions. I think the problem is with how I am performing the updates to the objects.
Cuboid:
function LightModule::createCuboid(%this, %images, %p3dHeight, %position, %scale, %heightOffset){
//Bottom
%bottom = new Sprite(){
//custom
Name = "Bottom";
Origin = %position;
Height = %heightOffset;
Scale = %scale / 100;
//standard
Position = %position;
class = "Cuboid";
Image = "LightModule:"@getWord(%images, 0);
SceneLayer = 2;
UpdateCallback = true;
};
//Side 1
%side1 = new Sprite(){
//custom
Name = "Side1";
Parent = %bottom;
//standard
Position = %position;
class = "Cuboid";
Image = "LightModule:"@getWord(%images, 2);
SceneLayer = 2;
};
//Side 2
%side2 = new Sprite(){
//custom
Name = "Side2";
Parent = %bottom;
//standard
Position = %position;
class = "Cuboid";
Image = "LightModule:"@getWord(%images, 3);
SceneLayer = 2;
};
//Side 3
%side3 = new Sprite(){
//custom
Name = "Side3";
Parent = %bottom;
//standard
Position = %position;
class = "Cuboid";
Image = "LightModule:"@getWord(%images, 4);
SceneLayer = 2;
};
//Side 4
%side4 = new Sprite(){
//custom
Name = "Side4";
Parent = %bottom;
//standard
Position = %position;
class = "Cuboid";
Image = "LightModule:"@getWord(%images, 5);
SceneLayer = 2;
};
//Top
%top = new Sprite(){
//custom
Name = "Top";
Height = %heightOffset + %p3dHeight;
Parent = %side1;
//standard
Position = %position;
class = "Cuboid";
Image = "LightModule:"@getWord(%images, 1);
SceneLayer = 2;
};
//add objects to scene
myScene.add(%bottom);
myScene.add(%side1);
myScene.add(%side2);
myScene.add(%side3);
myScene.add(%side4);
myScene.add(%top);
}Cylinder:
//Create a new cylinder with the designated properties
function LightModule::createCylinder(%this, %images, %p3dHeight, %position, %scale, %heightOffset){
%bottom = new Sprite(){
//custom
Name = "Bottom";
Origin = %position;
Height = %heightOffset;
Scale = %scale / 100;
//standard
Position = %position;
class = "Cylinder";
Image = "LightModule:"@getWord(%images, 0);
SceneLayer = 2;
UpdateCallback = true;
};
%middle = new Sprite(){
//custom
Name = "Middle";
Parent = %bottom;
//standard
Position = %position;
class = "Cylinder";
Image = "LightModule:"@getWord(%images, 1);
SceneLayer = 2;
//UpdateCallback = true;
};
%top = new Sprite(){
//custom
Name = "Top";
Height = %heightOffset + %p3dHeight;
Parent = %middle;
//standard
Position = %position;
class = "Cylinder";
Image = "LightModule:"@getWord(%images, 2);
SceneLayer = 2;
//UpdateCallback = true;
};
myScene.add(%bottom);
myScene.add(%middle);
myScene.add(%top);
}Update functions:
//==============================================================================
//update pseudo-3d effect for all sprite objects
//==============================================================================
function Sprite::onUpdate(){
updateObjects();
}
//==============================================================================
//handle movement and scale of pseudo-3d shapes
//==============================================================================
function updateObjects(){
//counters
%numberOfCylinders = 0;
%numBottomCylinder = 0;
%numTopCylinder = 0;
%numMiddleCylinder = 0;
%numberOfCuboids = 0;
%numBottomCuboid = 0;
%numTopCuboid = 0;
%numSide1 = 0;
%numSide2 = 0;
%numSide3 = 0;
%numSide4 = 0;
//Get a list of all primitives
for(%i = 0; %i < myScene.getCount(); %i++){
%sceneObject = getWord(myScene.getSceneObjectList(), %i);
//-------------Cylinders---------------
if(strcmp(%sceneObject.class, "Cylinder") == 0 && strcmp(%sceneObject.Name, "Bottom") == 0){
%bottom[%numBottomCylinder] = %sceneObject;
%numBottomCylinder++;
%numberOfCylinders++;
}else if(strcmp(%sceneObject.class, "Cylinder") == 0 && strcmp(%sceneObject.Name, "Top") == 0){
%top[%numTopCylinder] = %sceneObject;
%numTopCylinder++;
}else if(strcmp(%sceneObject.class, "Cylinder") == 0 && strcmp(%sceneObject.Name, "Middle") == 0){
%middle[%numMiddleCylinder] = %sceneObject;
%numMiddleCylinder++;
}
//-------------Cuboids---------------
else if(strcmp(%sceneObject.class, "Cuboid") == 0 && strcmp(%sceneObject.Name, "Bottom") == 0){
%bottomCuboid[%numBottomCuboid] = %sceneObject;
%numBottomCuboid++;
%numberOfCuboids++;
}else if(strcmp(%sceneObject.class, "Cuboid") == 0 && strcmp(%sceneObject.Name, "Top") == 0){
%topCuboid[%numTopCuboid] = %sceneObject;
%numTopCuboid++;
}else if(strcmp(%sceneObject.class, "Cuboid") == 0 && strcmp(%sceneObject.Name, "Side1") == 0){
%side1[%numSide1] = %sceneObject;
%numSide1++;
}else if(strcmp(%sceneObject.class, "Cuboid") == 0 && strcmp(%sceneObject.Name, "Side2") == 0){
%side2[%numSide2] = %sceneObject;
%numSide2++;
}else if(strcmp(%sceneObject.class, "Cuboid") == 0 && strcmp(%sceneObject.Name, "Side3") == 0){
%side3[%numSide3] = %sceneObject;
%numSide3++;
}else if(strcmp(%sceneObject.class, "Cuboid") == 0 && strcmp(%sceneObject.Name, "Side4") == 0){
%side4[%numSide4] = %sceneObject;
%numSide4++;
}
}
//------------------------------
//------ Cylinder Operations ---
//------------------------------
for(%i = 0; %i < %numberOfCylinders; %i++){
//---------Position---------
//set the position of the base
%magnitudeBottom = (mLog(Vector2Distance(Player.Position, %bottom[%i].Origin)) / (%bottom[%i].Height) ) / %bottom[%i].Scale;
%magnitudeTop = (mLog(Vector2Distance(Player.Position, %bottom[%i].Origin)) / ( (%top[%i].Height) ) ) / %bottom[%i].Scale;
%baseX = getWord(%bottom[%i].Origin, 0);
%baseY = getWord(%bottom[%i].Origin, 1);
%playerX = getWord(Player.Position, 0);
%playerY = getWord(Player.Position, 1);
%bottomX = %baseX + ((%baseX - %playerX)/ %magnitudeBottom);
%bottomY = %baseY + ((%baseY - %playerY)/ %magnitudeBottom);
%bottom[%i].Position = %bottomX SPC %bottomY;
//set the position of the top
%topX = %bottomX + ((%bottomX - %playerX)/ %magnitudeTop);
%topY = %bottomY + ((%bottomY - %playerY)/ %magnitudeTop);
%top[%i].Position = %topX SPC %topY;
//-----Scaling---------
%width = getWord(mySceneWindow.getWindowExtents(), 2);
%cameraHeight = 10;
//set scale of base
%bottom[%i].Size = %bottom[%i].Scale * ( %width / (%cameraHeight - %bottom[%i].Height ));
//set scale of top
%top[%i].Size = %bottom[%i].Scale * (%width / (%cameraHeight - %top[%i].Height));
%angle = -mRadToDeg( mAtan( getWord(Player.Position, 0) - getWord(%bottom[%i].Origin, 0), getWord(Player.Position, 1) - getWord(%bottom[%i].Origin, 1) ) ) + 180;
//------Stretching/deformation----------
%connectonPoints = getCylinderPoints(%top[%i], %bottom[%i], %angle);
%middle[%i].setSpritePolyCustom(%connectonPoints);
//%top[%i].setBlendAlpha(0.5);
}
//------------------------------
//------ Cuboid Operations -----
//------------------------------
for(%i = 0; %i < %numberOfCuboids; %i++){
//---------Position---------
//set the position of the base
%magnitudeBottom = (mLog(Vector2Distance(Player.Position, %bottomCuboid[%i].Origin)) / (%bottomCuboid[%i].Height) ) / %bottomCuboid[%i].Scale;
%magnitudeTop = (mLog(Vector2Distance(Player.Position, %bottomCuboid[%i].Origin)) / ( (%topCuboid[%i].Height) ) ) / %bottomCuboid[%i].Scale;
%cBaseX = getWord(%bottomCuboid[%i].Origin, 0);
%cBaseY = getWord(%bottomCuboid[%i].Origin, 1);
%playerX = getWord(Player.Position, 0);
%playerY = getWord(Player.Position, 1);
%cBottomX = %cBaseX + ((%cBaseX - %playerX)/ %magnitudeBottom);
%cBottomY = %cBaseY + ((%cBaseY - %playerY)/ %magnitudeBottom);
%bottomCuboid[%i].Position = %cBottomX SPC %cBottomY;
//set the position of the top
%cTopX = %cBottomX + ((%cBottomX - %playerX)/ %magnitudeTop);
%cTopY = %cBottomY + ((%cBottomY - %playerY)/ %magnitudeTop);
%topCuboid[%i].Position = %cTopX SPC %cTopY;
//---------Scaling----------
%width = getWord(mySceneWindow.getWindowExtents(), 2);
%cameraHeight = 10;
//set scale of base
%bottomCuboid[%i].Size = %bottomCuboid[%i].Scale * ( %width / (%cameraHeight - %bottomCuboid[%i].Height ));
//set scale of top
%topCuboid[%i].Size = %bottomCuboid[%i].Scale * (%width / (%cameraHeight - %topCuboid[%i].Height));
//---------Stretching/deformation----------
%connectonPoints = getCuboidPoints(%topCuboid[%i], %bottomCuboid[%i]);
%side1Connection = getWord(%connectonPoints, 0) SPC getWord(%connectonPoints, 1)
SPC getWord(%connectonPoints, 2) SPC getWord(%connectonPoints, 3)
SPC getWord(%connectonPoints, 10) SPC getWord(%connectonPoints, 11)
SPC getWord(%connectonPoints, 8) SPC getWord(%connectonPoints, 9);
%side2Connection = getWord(%connectonPoints, 2) SPC getWord(%connectonPoints, 3)
SPC getWord(%connectonPoints, 4) SPC getWord(%connectonPoints, 5)
SPC getWord(%connectonPoints, 12) SPC getWord(%connectonPoints, 13)
SPC getWord(%connectonPoints, 10) SPC getWord(%connectonPoints, 11);
%side3Connection = getWord(%connectonPoints, 4) SPC getWord(%connectonPoints, 5)
SPC getWord(%connectonPoints, 6) SPC getWord(%connectonPoints, 7)
SPC getWord(%connectonPoints, 14) SPC getWord(%connectonPoints, 15)
SPC getWord(%connectonPoints, 12) SPC getWord(%connectonPoints, 13);
%side4Connection = getWord(%connectonPoints, 6) SPC getWord(%connectonPoints, 7)
SPC getWord(%connectonPoints, 0) SPC getWord(%connectonPoints, 1)
SPC getWord(%connectonPoints, 8) SPC getWord(%connectonPoints, 9)
SPC getWord(%connectonPoints, 14) SPC getWord(%connectonPoints, 15);
%side1[%i].setSpritePolyCustom(%side1Connection);
%side2[%i].setSpritePolyCustom(%side2Connection);
%side3[%i].setSpritePolyCustom(%side3Connection);
%side4[%i].setSpritePolyCustom(%side4Connection);
}
}
//==============================================================================
//Handle the placement of the vertices of the middle piece of cylinders
//==============================================================================
function getCylinderPoints(%top, %bottom, %angle){
%tPoints = %top.getPosition();
%bPoints = %bottom.getPosition();
%bWidth = %bottom.getWidth();
%bHeight = 0;//change offset from center
%tWidth = %top.getWidth();
%tHeight = 0;//change offset from center
%bRad = 0.5 * mSqrt( (%bWidth * %bWidth) + (%bHeight * %bHeight) );
%tRad = 0.5 * mSqrt( (%tWidth * %tWidth) + (%tHeight * %tHeight) );
%bTheta0 = mAtan(%bHeight,%bWidth);
%bTheta1 = 3.141592 - %bTheta0;
%tTheta0 = mAtan(%tHeight,%tWidth);
%tTheta1 = 3.141592 - %tTheta0;
%bA = %bRad * mCos(mDegToRad(%angle) - %bTheta0) SPC %bRad * mSin(mDegToRad(%angle) - %bTheta0);
%bB = %bRad * mCos(mDegToRad(%angle) - %bTheta1) SPC %bRad * mSin(mDegToRad(%angle) - %bTheta1);
%tA = %tRad * mCos(mDegToRad(%angle) - %tTheta0) SPC %tRad * mSin(mDegToRad(%angle) - %tTheta0);
%tB = %tRad * mCos(mDegToRad(%angle) - %tTheta1) SPC %tRad * mSin(mDegToRad(%angle) - %tTheta1);
%bottomConnection0 = getWord(%bA, 0) + getWord(%bPoints, 0) SPC getWord(%bA, 1) + getWord(%bPoints, 1);
%bottomConnection1 = getWord(%bB, 0) + getWord(%bPoints, 0) SPC getWord(%bB, 1) + getWord(%bPoints, 1);
%topConnection2 = getWord(%tB, 0) + getWord(%tPoints, 0) SPC getWord(%tB, 1) + getWord(%tPoints, 1);
%topConnection3 = getWord(%tA, 0) + getWord(%tPoints, 0) SPC getWord(%tA, 1) + getWord(%tPoints, 1);
return %bottomConnection0 SPC %bottomConnection1 SPC %topConnection2 SPC %topConnection3;
}
//==============================================================================
//Find all the vertices on the top and bottom planes and return them
//==============================================================================
function getCuboidPoints(%top, %bottom){
%topPts = %top.getArea();
%bottomPts = %bottom.getArea();
%bp0 = getWord(%bottomPts, 0) SPC getWord(%bottomPts, 1);
%bp1 = getWord(%bottomPts, 2) SPC getWord(%bottomPts, 1);
%bp2 = getWord(%bottomPts, 2) SPC getWord(%bottomPts, 3);
%bp3 = getWord(%bottomPts, 0) SPC getWord(%bottomPts, 3);
%tp0 = getWord(%topPts, 0) SPC getWord(%topPts, 1);
%tp1 = getWord(%topPts, 2) SPC getWord(%topPts, 1);
%tp2 = getWord(%topPts, 2) SPC getWord(%topPts, 3);
%tp3 = getWord(%topPts, 0) SPC getWord(%topPts, 3);
return %bp0 SPC %bp1 SPC %bp2 SPC %bp3 SPC %tp0 SPC %tp1 SPC %tp2 SPC %tp3;
}Note: The setSpritePolyCustom function is one I implemented into the engine myself, and has been tested as being not responsible for the slowdown I am experiencing.
#2
05/23/2013 (8:11 pm)
I am using a release build. I will probably start implementing my math stuff into the engine and hopefully get better performance with more objects.
#3
It's the math. This is like 3D lite..... I would move it to C++ to speed things up.
Ron
05/23/2013 (9:15 pm)
Simon,It's the math. This is like 3D lite..... I would move it to C++ to speed things up.
Ron
#4
Maybe you can take a few cues from his work
You can find his repository and changes at the link below
github.com/pchan126/Torque2D
05/23/2013 (9:19 pm)
Community superstar Paul Jan has brought many math upgrades to T2D's math.Maybe you can take a few cues from his work
You can find his repository and changes at the link below
github.com/pchan126/Torque2D
#5
I had a feeling it was the math, but I wanted to run it by you guys before I started implementing it into the engine just in case I was handling something in a way that was inefficient.
Thanks for the help!
05/23/2013 (9:27 pm)
Cool, thanks for the link! I will definitely check that out!I had a feeling it was the math, but I wanted to run it by you guys before I started implementing it into the engine just in case I was handling something in a way that was inefficient.
Thanks for the help!
#6
05/23/2013 (10:17 pm)
Another thing -strcmp(%sceneObject.class, "Cylinder") // is equivalent to and probably slower than if (%sceneObject.class $= "Cylinder") // and is more cumbersome to write to boot....
#7
05/24/2013 (1:31 am)
I would be cautious about using some of my math functions through - I'm pretty sure that there are some errors in the matrix multiplication portions. The math upgrade was just the first step in the graphics update I'm still working on.
#8
05/24/2013 (7:54 am)
T3D has tested matrix math functions that you can borrow if you'd like....
Associate Simon Love
One thing that pops to mind though : Are you running a debug build or a release build? Debug builds are extremely slow when compared to their Release counterparts.