Quote:
Original post by WitchLord
It should perform well even for the default settings. I find it strange that you got the performance issue that you reported. Nobody else have reported this before. Some developers are even using AngelScript to do particle systems, which is something that have a very high number of iterations.
I definitely want to find out what the problem is here.
Cool, thanks for looking into it! From your description of other projects, I should be able to implement what I plan to, expecting good performance.
Quote:
Original post by WitchLord
Remove these two lines:
asIScriptModule *mod = scriptEngine->GetModule("MyModule"); int result = mod->GetFunctionIdByName(functionName.c_str());
These are notably slow, as they are currently doing simple linear searches. It would definitely be possible to improve the performance of them, but since they are not meant to be called frequently there is not much use in that.
Make these calls once, right after compiling the script, and store the function id for later use.
I did that, but it didn't do much difference. I agree that it's probably not relevant to improve their performance. I believe the bottleneck is elsewhere, either related to using script defined classes, or the fact that the script classes are using application registered classes through handles and/or values (I'm using both: "BasicSpriteEngine" is a handle and "Vector2" is a class type I defined myself, not the Vector2 you provide in Angelscript's source).
Quote:
Original post by WitchLord
Also, the script shows that TileMap is a class. But the runScript function is only implemented to call a global function. Where is the missing link?
Here is my complete script file, containing the class declarations and the main game cycle's code ("update", called every frame). The global "update" function called from the application is the last function, which calls "TileMap.update" (that single call is what disturbs the performance).
// container for a BasicEngineSprite and indication if it has already been called "update" or notclass Sprite{ Sprite(BasicEngineSprite@ imageSprite) { @this.imageSprite = imageSprite; this.hasUpdated = false; } BasicEngineSprite@ imageSprite; bool hasUpdated; // to ensure update is only called for this sprite once a cycle}// The class declarationclass Tile{ Tile(Vector2 position, Sprite@ sprite) // The default constructor { this.position = position; @this.sprite = sprite; } ~Tile() {} void resetHasUpdated() { this.sprite.hasUpdated = false; } void update(float timeSinceLastUpdate) { //this.imageSprite.update(timeSinceLastUpdate); // update animation state if(!this.sprite.hasUpdated) { this.sprite.imageSprite.update(timeSinceLastUpdate); // update animation state this.sprite.hasUpdated = true; } } void draw(Vector2 tileOffset) { // update position based on this object's index layer //print("final tile pos: "+ (this.position + tileOffset).str() +"\n"); this.sprite.imageSprite.setPosition(this.position + tileOffset); this.sprite.imageSprite.draw(); } // class properties Vector2 position; // x,y position of sprite within tile Sprite@ sprite; // reference sprite to draw as tile //uint8 layerIndex; // layer index for this tile (0 = deepest BG)}class TileMap{ TileMap(uint totalTilesX, uint totalTilesY, uint tileWidth, uint tileHeight) { this.totalTilesX = totalTilesX; this.totalTilesY = totalTilesY; this.tileWidth = tileWidth; this.tileHeight = tileHeight; this.totalLayers = 10; // Resize it to desired dimension this.tileMap.resize(this.totalTilesX); for(uint idxColumn = 0; idxColumn < this.totalTilesX; ++idxColumn) this.tileMap[idxColumn].resize(totalTilesY); } void update(float timeSinceLastFrame) // update tile properties { for(uint idxColumn = 0; idxColumn < this.totalTilesX; ++idxColumn) { for(uint idxLine = 0; idxLine < this.totalTilesY; ++idxLine) {// //print(" Updating y = "+ idxLine + "\n");// if(this.tileMap[idxColumn][idxLine] !is null)// {// //print("Updating tile ["+ idxColumn +"],["+ idxLine +"]\n");// Vector2 tileOffset(this.tileWidth * idxColumn, this.tileHeight * idxLine);// //print("tileoffset: "+ tileOffset.str() +"\n");// this.tileMap[idxColumn][idxLine].update(timeSinceLastFrame);// //print("updating ["+ idxColumn +"]["+ idxLine +"]");//// this.tileMap[idxColumn][idxLine].draw(tileOffset);// } } } // draw tilemap grid //this.drawTilemapGrid(); // reset all tiles "updated" status for(uint idxColumn = 0; idxColumn < this.totalTilesX; ++idxColumn) { uint idxLine = 0; for(uint idxLine = 0; idxLine < this.totalTilesY; ++idxLine) { //if(this.tileMap[idxColumn][idxLine] !is null) // this.tileMap[idxColumn][idxLine].resetHasUpdated(); } } } void addTile(Tile@ tile, uint tileX, uint tileY, uint layerIndex) // tile and tilemap x,y and layer coordinates { @this.tileMap[tileX][tileY] = tile; } void drawTilemapGrid() { // draw column lines for(uint idxColumn = 0; idxColumn <= this.totalTilesX; ++idxColumn) { Vector2 lineStart(idxColumn * tileWidth, 0); Vector2 lineEnd(idxColumn * tileWidth, totalTilesY * tileHeight); basicEngine.drawLine(lineStart, lineEnd, 1.0f, 0, 0, 255, 255); } // draw row lines for(uint idxLine = 0; idxLine <= this.totalTilesY; ++idxLine) { Vector2 lineStart(0, idxLine * tileHeight); Vector2 lineEnd(totalTilesX * tileWidth, idxLine * tileHeight); basicEngine.drawLine(lineStart, lineEnd, 1.0f, 0, 0, 255, 255); } } // properties Tile@[][] tileMap; // tileMap[1] is x = 1, tilemap[1][2] is x = 1, y = 2 uint totalTilesX; uint totalTilesY; uint tileWidth; uint tileHeight; uint totalLayers;}float scrollSpeed = 300.0f;TileMap tm;void initialize(){ basicEngine.loadResourceImage("Resources/Gfx/test_anim1.png","img1"); basicEngine.loadResourceImage("Resources/Gfx/test_anim2.png","img2"); basicEngine.loadResourceImage("Resources/Gfx/test_anim3.png","img3"); basicEngine.loadResourceImage("Resources/Gfx/test_anim4.png","img4"); basicEngine.loadResourceImage("Resources/Gfx/tile1_64x.png","tile1"); BasicEngineSprite@ ball = basicEngine.createSprite("Sprite1"); // correct way to get pointers basicEngine.addImageToSprite("Sprite1", "img1", 0.25f); basicEngine.addImageToSprite("Sprite1", "img2", 0.25f); basicEngine.addImageToSprite("Sprite1", "img3", 0.25f); basicEngine.addImageToSprite("Sprite1", "img4", 0.25f); BasicEngineSprite@ besTile1 = basicEngine.createSprite("Tile1"); basicEngine.addImageToSprite("Tile1", "tile1", 0);// basicEngine.addButton("buttonB", "Button", Vector2(10,10), Vector2(0,0)); Sprite spriteBall(ball); Tile tile1(Vector2(10,10), spriteBall); Tile tile2(Vector2(10,10), spriteBall); Tile tile3(Vector2(0,0), spriteBall); Tile tile4(Vector2(0,0), spriteBall); Sprite spriteWall1(besTile1); Tile tileWall1(Vector2(0,0), spriteWall1); tm = TileMap(1000, 10, 64, 64); tm.addTile(tile1, 0, 0, 0); tm.addTile(tile2, 2, 0, 0); tm.addTile(tile3, 2, 1, 0); tm.addTile(tile4, 2, 2, 0); tm.addTile(tileWall1, 0, 1, 0);}void update(){ float timeSinceLastUpdate = basicEngine.getElapsedTime(); //print(" elapsed time:"+ timeSinceLastUpdate + "\n"); Vector2 mousePosition(basicEngine.getMouseX(), basicEngine.getMouseY()); //basicEngine.drawRectangle(mousePosition, Vector2(40,20), 255,100,100,255); if(mousePosition.getX() > 800 - 50) basicEngine.setCameraPosition(basicEngine.getCameraPosition() + Vector2(scrollSpeed * timeSinceLastUpdate,0)); else if(mousePosition.getX() < 0 + 50) basicEngine.setCameraPosition(basicEngine.getCameraPosition() - Vector2(scrollSpeed * timeSinceLastUpdate,0)); Vector2 mousePositionWorld = basicEngine.convertCameraToWorldCoordinates(mousePosition); //ball.setPosition(mousePositionWorld); // update tilemap tm.update(timeSinceLastUpdate); // commenting this line gives about 500 fps, with it is at about 40/50 // exit on esc press //if(basicEngine.keyPressed(Event::Input::Keyboard::Code::Escape)) // basicEngine.endMainCycle();}
I'll look into re-compiling and trying the other tips in the weekend.