I am working with AndEngine for an app project and I have hit a major snag in regards to my frame rate. I have a few decently sized sprites to place on the screen, each being 512x768, and it seems that each one of these I add takes a very noticeable chunk of my FPS away.
Even if the image being used is nothing but a blank PNG, there is an equivalent amount of loss. I have searched around and tried everything that made sense, but nothing seems to have improved it at all, and the lack of documentation for AndEngine doesn't simplify matters any.
My only real guess at the reason is that the sprites must be entirely recreating themselves every call. I could be entirely wrong, but it's the only logical reason I can think of. Despite that, I am not sure how to stop this from happening (Still assuming it is the problem at all of course).
The code I am using to create everything is the same as every example I've seen, so I doubt that is the problem, but just in case my sprites are setup more or less like the following :
public void onLoadResources(){
this.mTexAtlas = new BitmapTextureAtlas(1024, 1024, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
this.mTexBottom = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mTexAtlas, this, "bottom.png", 0, 0);
this.getEngine().getTextureManager().loadTexture(this.mTexAtlas);
}
public Scene onLoadScene(){
mTexBottom = new Sprite(spriteX, spriteY, spriteWidth, spriteHeight, mTexAtlas);
scene.attachChild(mTexBottom, childCount++);
}
It's not my exact code, for clarity reasons, but that is how all of the examples I have seen look, so that's pretty much how mine looks. Oh, and the texture atlas is 1024 wide because I am putting two images on each, at least for right now.
At this point I am willing to try anything to get it going a little better, so any ideas at all would be great.
I think you are using the wrong variables in the wrong places, could you try it like this?
public void onLoadResources(){
this.mTexAtlas = new BitmapTextureAtlas(1024, 1024, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
this.mTexBottom = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mTexAtlas, this, "bottom.png", 0, 0);
this.getEngine().getTextureManager().loadTexture(this.mTexAtlas);
}
public Scene onLoadScene(){
Sprite theSprite = new Sprite(spriteX, spriteY, spriteWidth, spriteHeight, mTexBottom );
scene.attachChild(theSprite, childCount++);
}
How big is your Camera? I mean how big are your Sprites compared to the screen?
You should try to avoid drawing the screen more than once. Drawing a couple of Sprites that cover the whole screen is probably the worst thing you could do.
Related
I've been receiving a strange error after hot-reloading my code:
Logs (I'll provide them in text form if needed)
The error references a Notice Range Sphere component. It's just a UDetectionSphere, a simple wrapper for USphereComponent. It used to work correctly, I think the problems begun when I re-parented BaseEnemy from ACharacter to ABaseEntity (see class graph). The game seems to work fine, but the fact that there is an error can't be a good thing. I also can't edit component's properties in editor (both for notice and forget range spheres and for some reason arrow component inherited from ACharacter). Again, it used to work correctly and I was able to edit it. Here's how those components are declared (BaseEnemy.h):
public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Setup")
UDetectionSphere * NoticeRangeSphere;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Setup")
UDetectionSphere * ForgetRangeSphere;
I'm pretty sure the error in logs is a simple fix, but I don't even know where to start looking. I can't find this error in google, so it's probably something trivial I'm overlooking. How do I go about fixing this?
So I'm writing a boid simulation program as a project for school. My program supports multiple different groups of these boids that don't flock with other groups, they all have different settings which I do by adding a BoxPanel to the main GUI of the program when a new tribe is made, and those BoxPanels have a settings button that opens a new frame with the groups settings.
This works perfectly when I start the program up and add all the pre defined tribes that are in the code. Now I made a new part of the GUI that let's you make new groups of these boids and adds them while the simulation is running, and here is when the problems start for me.
For some weird reason it adds the group just fine, with the right settings in to the simulation but it wont add the BoxPanels to the main GUI. It makes the whole settings bar that I have in the side of my simulation disappear completely. I tested this out and if I add the tribes in the beginning of my calculation thread it does the same thing, so this seems to be a problem with multiple threads and swing. Any ideas what is causing this or how to fix this? I am completely perplexed by this.
tl;dr: The code below for adding tribes works fine when I haven't started the thread but if I try to use it after starting the thread the optionPanel appears empty.
Here's the code that adds the BoxPanels to the main gui:
def addTribe(tribe: Tribe) = {
tribeFrames += new TribeSettingFrame(tribe)
tribeBoxPanels += new TribeBoxPanel(tribe)
this.refcontents
}
private def refcontents = {
top.optionPanel.contents.clear()
top.optionPanel.contents += new BoxPanel(Orientation.Vertical) {
tribeBoxPanels.foreach(contents += _.tribeBoxPanel)
}
top.optionPanel.contents += new BoxPanel(Orientation.Horizontal) {
contents += top.addTribeButton
}
top.optionPanel.contents += new BoxPanel(Orientation.Horizontal) {
contents += top.vectorDebugButton
}
}
new Thread(BoidSimulation).start()
Oh and I tested if it really adds the contents that it should by printing out the sizes of the contents, and everything matches fine, it just won't draw them.
EDIT: After some digging around it really seems to be a thing with updating swing from a Thread. A lot of places suggest to use SwingWorker but from the info I gathered about it I don't think it would fit in my program since it is a continuous simulation and and I would have to keep making new SwingWorkers every frame.
EDIT2: Tried calling the method from the thread like this:
SwingUtilities.invokeLater(new Runnable() {
override def run() {
GUI2D.addTribe(tribe)
}
});
Didn't make any difference. I am starting to think that this is a problem with how I use TribeBoxPanel and TribeSettingFrame. These are objects that both contain only one method that returns the wanted BoxPanel or Frame. Is this implementation bad? If so what is the better way of creating dynamic BoxPanels and Frames?
Swing is not thread-safe.
Repeat after me.
Swing is not thread-safe.
Hear the chorus? Swing is not thread safe There is official documentation.
There is a very simple workaround given as well.
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
// your stuff
}
});
In Scala, this is supported as:
Swing.invokeLater(/* your stuff */)
First you should let the UI thread handle all UI manipulation.
The simple way should be following Scala-Code:
Swing.onEDT { GUI2D.addTribe(tribe) }
But as you already noted, this won't solve your problem. I had a very similar problem where I only changed the text content of a Swing.Label and it sometimes simply disappeared.
It turned out that it only disappeared, when the text was too long to display it inside the Area which the Label initially reserved for itself. So one way around your Problem could be to give the optionPanel a bigger initial size when you create it.
Swing.onEDT { top.optionPanel.preferredSize = new Dimension(width,height) }
I'm not quite sure whether this has to be set before the component is first drawn (before Frame.open() is called).
To stop my application from flickering, I tried to activate DoubleBuffering for all of my controls and subcontrols.
To achieve this, I added the follwoing codesnippet in my mainform:
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; //WS_EX_COMPOS
return cp;
}
}
The problem is, that with WindowsXP the cpu-load becomes almost 100% and keeps up. No problem on Windows7.
It looks for me, as it is the very same problem as in this question. Is there a "easy" solution in C#? Or asked in a different way -> What usually causes this behaviour? So I can find out the problem in my application.
UPDATE: Maybe some more information to help you folks help me. What I am trying to do is showing a semi-transparent form ontop of the mainform with an progressbar. This "progressBarForm" is in a second thread to have this progressbar running. On Win7 everything works fine, as mentioned above with WinXP (.net4, activated desktoptheme) there is 100% cpu-load after the progressbar was shown once - also the acutal payload-function needs much longer to complete - maybe because of the high-cpu-load done by the progressbar. Where and what should I check again? Some ideas?
Btw.: I don't think the thread is a problem, as when I show the form in the mainthread and don't refresh anything, the result (high cpu-load) is the same...
Here is something strange concerning AutorotateToInterfaceOrientation.
In the Debugger console I get this message for one of my view controllers :
The view controller returned NO from
-shouldAutorotateToInterfaceOrientation: for all interface orientations. It should support at least one orientation.
But in reality the rotations works perfectly well. And the message is wrong. Here is the code for -shouldAutorotateToInterfaceOrientation:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return ([centerPoint autoRotateFlag]||(interfaceOrientation==centerPoint.userOrientation));
}
And either autoRotateFlag is simply true (YES), or if it is not centerPoint.userOrientation has been fixed to one of the four acceptable value.
This has been working for me for a long time and the app still works. I just don't know where this message is coming from.
Any idea?
By putting some tracing in my software, using NSLog; I realized that
shouldAutorotateToInterfaceOrientation was called seven times before
viewDidLoad was called.
Since my variable 'autoRotateFlag' is only initialized when passing through viewDidLoad. That explains my problem.
I have to admit though, that I was far from thinking shouldAutorotateToInterfaceOrientation could be called before viewDidLoad.
Obviously I was wrong. And I still do not fully understand the order in which all those methods are called.
I'm writing a mobile phone game using j2me. In this game, I am using multiple Canvas objects.
For example, the game menu is a Canvas object, and the actual game is a Canvas object too.
I've noticed that, on some devices, when I switch from one Canvas to another, e.g from the main menu to the game, the screen momentarily "flickers". I'm using my own double buffered Canvas.
Is there anyway to avoid this?
I would say, that using multiple canvases is generally bad design. On some phones it will even crash. The best way would really be using one canvas with tracking state of the application. And then in paint method you would have
protected void paint(final Graphics g) {
if(menu) {
paintMenu(g);
} else if (game) {
paintGame(g);
}
}
There are better ways to handle application state with screen objects, that would make the design cleaner, but I think you got the idea :)
/JaanusSiim
Do you use double buffering? If the device itself does not support double buffering you should define a off screen buffer (Image) and paint to it first and then paint the end result to the real screen. Do this for each of your canvases. Here is an example:
public class MyScreen extends Canvas {
private Image osb;
private Graphics osg;
//...
public MyScreen()
{
// if device is not double buffered
// use image as a offscreen buffer
if (!isDoubleBuffered())
{
osb = Image.createImage(screenWidth, screenHeight);
osg = osb.getGraphics();
osg.setFont(defaultFont);
}
}
protected void paint(Graphics graphics)
{
if (!isDoubleBuffered())
{
// do your painting on off screen buffer first
renderWorld(osg);
// once done paint it at image on the real screen
graphics.drawImage(osb, 0, 0, Tools.GRAPHICS_TOP_LEFT);
}
else
{
osg = graphics;
renderWorld(graphics);
}
}
}
A possible fix is by synchronising the switch using Display.callSerially(). The flicker is probably caused by the app attempting to draw to the screen while the switch of the Canvas is still ongoing. callSerially() is supposed to wait for the repaint to finish before attempting to call run() again.
But all this is entirely dependent on the phone since many devices do not implement callSerially(), never mind follow the implementation listed in the official documentation. The only devices I've known to work correctly with callSerially() were Siemens phones.
Another possible attempt would be to put a Thread.sleep() of something huge like 1000 ms, making sure that you've called your setCurrent() method beforehand. This way, the device might manage to make the change before the displayable attempts to draw.
The most likely problem is that it is a device issue and the guaranteed fix to the flicker is simple - use one Canvas. Probably not what you wanted to hear though. :)
It might be a good idea to use GameCanvas class if you are writing a game. It is much better for such purpose and when used properly it should solve your problem.
Hypothetically, using 1 canvas with a sate machine code for your application is a good idea. However the only device I have to test applications on (MOTO v3) crashes at resources loading time just because there's too much code/to be loaded in 1 GameCanvas ( haven't tried with Canvas ). It's as painful as it is real and atm I haven't found a solution to the problem.
If you're lucky to have a good number of devices to test on, it is worth having both approaches implemented and pretty much make versions of your game for each device.