I have been developing my java game for around 1.5 years now, and it has been running with around 3200 FPS on my PC (Intel I7, GTX 970, 8GB RAM).
However a few days back I tried it on my LAPTOP (Intel I7, GTX 1050TI, 16GB RAM). It's hardware is similar to my PC, however it barely hits 50 FPS. I noticed the GPU usage is 0 when running my game (on the laptop, unsure about PC). This difference seems abnormally big compared to the difference on the 2 machine.
I set the GTX 1050TI as first GPU, it increased the FPS from 30 to 50 on the laptop, still the usage is 0 (MSI Afterburner).
The two for loops below alone takes up 10 miliseconds on the laptop, but it runs fine on the PC, so I don't think so it is an optimization problem.
int xStart = (int) Math.max(0, handler.getGameCamera().getxOffset() / Tile.TILEWIDTH);
int xEnd = (int) Math.min(width, (handler.getGameCamera().getxOffset()
+ handler.getWidth()) / Tile.TILEWIDTH + 1);
int yStart = (int) Math.max(0, handler.getGameCamera().getyOffset() / Tile.TILEHEIGHT);
int yEnd = (int) Math.min(height, (handler.getGameCamera().getyOffset()
+ handler.getHeight()) / Tile.TILEHEIGHT + 1);
for(int y = yStart; y < yEnd; y++) {
for(int x = xStart; x < xEnd; x++) {
getTile(x, y).render(g, (int) (x * Tile.TILEWIDTH
- handler.getGameCamera().getxOffset()),
(int) (y * Tile.TILEHEIGHT - handler.getGameCamera().getyOffset()));
}
}
Looking at the hardware of both the PC and the LAPTOP, the FPS should be similar. Is it the GPU usage, or something else?
--UPDATE:
The GPU is working now! on 60% usage, so
I managed to get the laptop to 400FPS, with OPENGL hardware acceleration
Still, is 3200 FPS - 400 FPS realistic for two machines that are this similar in terms of hardware?
Related
I have recently started programming games in java. I come from a C# / XNA background and i already have experience in game development.
However I have a problem in my java game. I have a bouncing script which makes a in-game "particle" bounce upon collision with a solid surface, such as the ground.
Here is a snippet of the code that manages the bouncing.
private final void respondY(Rectangle r)
{
if(!r.intersects(getBounds())) // If not colliding, return
return;
if(Yvel > 0) // If falling...
{
if(r.y < Y + Height) //Another collision test
{
Y = r.y - Height; // Set Y to top of object
Yvel *= -bounce; // Bounce (Here is the problem)
onFloor = true;
}
}
else if(Yvel < 0) // If hit ceiling
{
if(Y < r.y + r.height) // Collision test
{
Y = r.y + r.height; // Set Y to bottom of object
Yvel = 0; // No bouncing here
}
}
}
The problem is that the object bounces upon the floor as it should, but after a while the object bounces constantly at the same height where I want it to stop bouncing when it got to that constant height.
NOTE:
Yvel is a int that is the vertical velocity of the object
Bounce is a float that controls how "bouncy" a object is. e.g. 0.5 means that it bounces half as high as it fell
Thanks in advance! Please note that this is my first post so if I make mistakes please point them out in a constructive manner.
The float (and double) types are imprecise. This especially causes problems when dealing with very small numbers - in fact there's a smallest representable number and a finite quantity of possible numbers that can be represented (and bit like quantum physics). The number stored by a float is actually the closest number possible to represent to the calculation result.
What's happening is the velocity calculation never reaches zero, because the result of multiplying the smallest number float can represent by a value >= .5 is itself.
I would force it to zero by putting a low threshold on the calculation result:
Yvel = Yvel * -bounce;
if (Yvel < .000001F)
Yvel = 0;
I am making an app for android, in which at some point i need to add a lot of levels. To be efficient, after the player leaves a level, i delete it and add a new level, depending on some factors. The problem is, as I advance through the levels, the game gets a lot of lag. I looked on memory with device monitor and I saw that the memory used keeps going up, even if I use .clear to delete previous levels. I will put the code in and I tested it only with the player, without any other entities:
void manageLevels(){
while(inc < sf && inc < minLevel){
blocks.get(0).clear();
inc++;
}
while(sf < numberLevels && sf < maxLevel + 2){
blocks.add(new ArrayList<blockClass>());
sf++;
nrLv[sf] = blocks.size() - 1;
float BlockX = -1500 * scaleX, BlockY = 250 * scaleY - (sf - 1) * levelSize;
platforms[sf] = BlockY + 100 * scaleY;
setTexture();
for(int i = 0 ; i < numberOfBlocks ; i++){
blocks.get(nrLv[sf]).add(new blockClass(BlockX, BlockY, typeT, scaleX, scaleY));
BlockX += 100 * scaleX;
}
}
}
Have been playing around with some basic 3D. I'm trying to keep the math relatively simple as I'm only in year 9.
Background info:
I have 3 int[] variables called xpoints, ypoints and zpoints. I was thinking about putting them all in one List called nodes but decided it's easier not to.
The first forumla I tried was:
xpoints[i] = (int) (r*Math.cos(Math.toRadians(d)));
ypoints[i] = (int) (r*Math.sin(Math.toRadians(d)));
This worked perfectly for rotating the cube around one axis but not any others. I found a formula that looked promising for multiple axis but can't get it to work. The faces seem to shrink slightly during each loop, ending up in a single point (the centre).
xpoints[i] = (int) (x * cos_t - y * sin_t)
ypoints[i] = (int) (y * cos_t + x * sin_t)
The full function applying the math:
public void rotateZ(double theta){
theta = Math.toRadians(theta);
double cos_t = Math.cos(theta);
double sin_t = Math.sin(theta);
for (int i = 0; i < xpoints.length; i++){
double x = xpoints[i] - x_off;
double y = ypoints[i] - y_off - ypoints_mod[i];
xpoints[i] = (int) (x * cos_t - y * sin_t) + x_off;
ypoints[i] = (int) (y * cos_t + x * sin_t) + y_off + ypoints_mod[i];
System.out.println(x+", "+y);
}
}
If you need anymore info please let me know (wasn't quite sure how to word this)
Thanks,
amazing work for a 9 years old boy!! Great!!
search for euler rotation for rotating a point or vector on all 3-axis.
Well... Don't you just love computer programming :). As shown in the code I was rounding the result to an Integer for convenience. Turns out this breaks it completely, removed that and it works fine.
DON'T ROUND WHEN DOING MATH ON COMPUTERS!!! :P
Never again
So I'm rendering a tilemap (simply a twodimensional array with MapTiles), called WorldGeneration, using a isometric renderer class I've created. The camera I'm using uses 64 pixels per meter, so its height for example is: (game window height)/64. The SpriteBatch used in the isometric renderer has it's projection matrix set to this camera. (batch.setProjectionMatrix(cam.combined)
The problem is, I'm getting horrible performance when rendering textures onto this SpriteBatch. I'm not sure if it's caused by the projection matrix being what it is (needing to scale my 64x64 textures to 1x1 in batch dimensions), or something else.
I've tried running the program without executing the batch.draw call in the renderer (see code below) and everything works fine. Is anyone able to find the problem or give me some tips?
Relevant code snippets:
Render method of the isometric renderer:
public void render(WorldGeneration gen) {
//TODO compensate for elevation
int x1 = (int) (cameraIso.x - 23); // TODO compensate for zoom
int x2 = (int) (cameraIso.x + 23);
int y1 = (int) (cameraIso.y - 23);
int y2 = (int) (cameraIso.y + 23);
if(x1 < 0){
x1 = 0;
}else if(x1 >= gen.getLengthX()){
x1 = gen.getLengthX() - 1;
}
if(y1 < 0){
y1 = 0;
}else if(y1 >= gen.getLengthY()){
y1 = gen.getLengthY() - 1;
}
if(x2 < 0){
x2 = 0;
}else if(x2 >= gen.getLengthX()){
x2 = gen.getLengthX() - 1;
}
if(y2 < 0){
y2 = 0;
}else if(y2 >= gen.getLengthY()){
y2 = gen.getLengthY() - 1;
}
batch.begin();
for (int x = x2; x >= x1; x--) {
for (int y = y2; y >= y1; y--) {
tiles = gen.getTiles(x, y);
if(tiles == null){
continue;
}else if(tiles.size <= 0){
continue;
}
for(MapTile tile: tiles){
if(tile.getOpacity() < 1){
batch.setColor(batchColor.r, batchColor.g, batchColor.b, tile.getOpacity());
}else{
batch.setColor(batchColor.r, batchColor.g, batchColor.b, 1);
}
//TODO only visible (not underneath several tiles)
pos.x = x;
pos.y = y;
//As you can see the texture is scaled to 1x1 because of batch:
batch.draw(textures[tile.getId()], translateCartToIso(pos).x,
translateCartToIso(pos).y + tile.getZ(), 1f, 1f);
}
}
}
batch.end();
}
As you can see I've even created the Vector2 pos outside the render method to increase performance, but I'm not sure if that's even necessary. It is also worth noting that tiles are locked to a xy grid, but their z value is not, that is why an array is needed.
Edit: Somehow the performance is great if the camera is zoomed out, have no idea why this is. It definitely has something to do with the camera dimensions.
Found the answer, it actually had to do with the graphics behind everything. I noticed that when I ran stress tests my computer (mac) would shut down because of a graphics problem.
It basically came down to this line:
cfg.useHDPI = true;
Where I made my LwjglApplicationConfiguration use HD pixels, I guess my computer couldn't handle it when it had to process too many HD pixels (that's why it worked when i zoomed the camera out, less pixels)
I guess I'll have to deal with some distorted pixels for now, that's a problem I'll have to solve later!
I'm not exactly positive on everything your code is doing, but it looks like the outermost loop has a runtime of O(56), the inner for loop has another O(56) runtime, and then the innermost foreach loop has a runtime of O(<# of elements in tiles>) giving you a grand total of: around 3,000 draw calls, assuming one element in tiles.
That's already quite a bit of drawing, not to mention the performance decrease scaling can often impart. Is there no way to optimize that?
I have two images, one for a zombie and one for a blade that the zombie will have a 10 % chance to spawn with. I want to position the blade so that it will overlap the zombies right hand. I would be able to do this if the zombie was the same height as width but because it is 62x55 it makes everything much more complex. The code that positions the blade and the zombies right now looks like this:
at = new AffineTransform();
angle = Math.atan2(player.getY() - zombie.getY(), player.getX() - zombie.getX()) + (Math.PI / 2);
at.setToTranslation(zombie.getX(), zombie.getY());
at.rotate(angle, zombie.getWidth() / 2, zombie.getHeight() / 2);
g2d.drawImage(zombie.getBrImage(),at,this);
ImageIcon ii = new ImageIcon("Blade.png");
Image image = ii.getImage();
int x = (int) Math.round(zombie.getX() + 47 * Math.sqrt(2) * Math.cos(angle - Math.PI / 4));
int y = (int) Math.round(zombie.getY() + 47 * Math.sqrt(2) * Math.sin(angle - Math.PI / 4));
at.setToTranslation(x, y);
at.rotate(angle, zombie.getWidth() / 2, zombie.getHeight() / 2);
g2d.drawImage(image, at, this);
This will produce the following result:
As you can see the blade is positioned at a higher y (lower y if you count 0 as the top of the screen) than is should, because the zombie will rotate so that it always faces the player I can't just change the number 47 for y because then the blade wont rotate properly.
So how would I make the blade always be positioned properly so that it would always produce the following result no matter what angle the zombie is facing?
You could have two images:
one without the blade (Img1)
one with the blade (Img2): taking the zombie and the blade, and compositing it at the beginning, e.g. in the constructor.
Then you could just say:
if (randomValue < 0.10) { zombieImg = Img1 } else { zombieImg = Img2}
And then just translate/rotate/etc. the ZombieImg after the initialization.
What do you think? :-)