Ok, so I have a game I just started and I am kind of stuck on the smooth scrolling. I have the basic scrolling part done but my background (Grid) only moves by intervals of 50.
for (int x = (getPlayerX() / getTileSize()) - 6; x < (getPlayerX() / getTileSize()) + 9; x++)
{
for (int y = (getPlayerY() / getTileSize()) - 5; y < (getPlayerY() / getTileSize()) + 8; y++)
{
int xPos = ((x - (getPlayerX() / tileSize)) + (getScreenX() / tileSize) - 1) * tileSize;
int yPos = ((y - (getPlayerY() / tileSize)) + (getScreenY() / tileSize) - 1) * tileSize;
if (x > 0 && x < mapX && y > 0 && y < mapY)
{
if (getTiles()[x][y].tileID == 0)
{
g.drawRect(xPos, yPos, tileSize, tileSize);
}
if (getTiles()[x][y].tileID == 1)
{
g.fillRect(xPos, yPos, tileSize + 1, tileSize + 1);
}
}
}
}
Sorry about the subtraction and addition in the for loops, I have them set up so it will display from 1 to whatever instead of 0 to whatever - 1.
So basically I want to redraw the grid every pixel I move, instead of every 50. Put I dont want to iterate over every pixel on the screen
Ok, at first you are confusing with the background and the grid. A grid is a way to check collisions and a spatial partitioning algorithm that never moves. A background is an image which is drawn behind every entity in your game in every level.
What you are trying to do is make the level scroll, as per what I understand. To do so, we create a class called View also called as a Camera which draws the background and the visible entities by centering the entity which is controlled by the player.
And to center an entity and draw the map, I use these classes. Hope you understand that I wrote them in C#.
Map
MapInfo
MapLayer
MapLoader
MapManager
MapView
And here is my implementation of Grid. I have the java versions of the same classes here but I haven't implemented the Grid class in java.
You can read my tutorial Using Grids For Collisions for more info on how it works. Hope it helps.
Related
I would like to create circles with a random diameter, position and color in a panel with the Graphics class in Java. It works fine, however I have the problem that often circles touch or overlap the border.
How can I make the circles fully stay within the panel?
Thanks in advance!
This is the code I use for creating the circles:
amount = rnd.nextInt(10);
for (int i = 0; i < amount; i++){
x = (50 + rnd.nextInt(panel.getWidth() - 50 + 1)) - 50;
y = (50 + rnd.nextInt(panel.getHeight() - 50 + 1)) - 50;
diameter = (rnd.nextInt(100));
gr.setColor(new Color(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256)));
gr.fillOval(x, y, diameter, diameter);
gr.drawString("" + (panel.getHeight() - y), x, y);
}
x = (50 + rnd.nextInt(panel.getWidth() - 50 + 1)) - 50;
y = (50 + rnd.nextInt(panel.getHeight() - 50 + 1)) - 50;
diameter = (rnd.nextInt(100));
How can you calculation the x/y position if you don't know what the diameter of the circle is going to be?
First you need to calculate the diameter. Then you need to use the diameter to make sure the x/y plus the diameter is less than the width of the panel.
I don't understand the point of adding 50 and then subtracting 50. I would think the random number should be the width minus the diameter.
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 been following a 2d side scroller tutorial in java and have got the basics working, I changed the code a bit to make it so that the tiles and background are always moving, this worked as i intended. The relevant code is below:
Within the character class:
if (speedX < 0) {
centerX += speedX;
}
if (speedX == 0 || speedX < 0) {
bg1.setSpeedX(0);
bg2.setSpeedX(0);
}
if (centerX <= 350 && speedX > 0) {
centerX = centerX + speedX ;
}
if (speedX > 0 && centerX > 350) {
bg1.setSpeedX(-MOVESPEED / 4);
bg2.setSpeedX(-MOVESPEED / 4);
}
Within the tile class:
speedX = bg.getSpeedX() * 3;
tileX = tileX + speedX - 4;
I wanted a way to make it so that if the character moves left, the tiles + background move slower. I am having issues with variable scope and setters/getters. Within the main game class, I have the code:
case
KeyEvent.VK_LEFT:
character.moveLeft();
character.setMovingLeft(true);
break;
How can i include an if statement within the tile class that reads whether the character is moving left (determined from a keyPressed event in the main game class) and adjusts the speed of the tiles accordingly?
I want to write something to the effect of:
if (setMovingLeft = true){
speedX = bg.getSpeedX() * 3;
tileX = tileX + speedX - 1; << changed from - 4
Obviously this doesn't work, can anyone suggest a way to accomplish this? I can provide more information if needed.
So, I'm creating a simple 2D video game. I noticed recently that the player can move off the screen, so I added this code:
if (newX <= SIZE * TagsCanvas.SCALE) {
newX = SIZE * TagsCanvas.SCALE;
} else if (newX >= TagsCanvas.CANVAS_WIDTH - (SIZE * TagsCanvas.SCALE) - getAABB().getRadX()) {
newX = TagsCanvas.CANVAS_WIDTH - (SIZE * TagsCanvas.SCALE) - getAABB().getRadX();
}
if (newY <= SIZE * TagsCanvas.SCALE) {
newY = SIZE * TagsCanvas.SCALE;
} else if (newY >= TagsCanvas.CANVAS_HEIGHT - (SIZE * TagsCanvas.SCALE) - getAABB().getRadY()) {
newY = TagsCanvas.CANVAS_HEIGHT - (SIZE * TagsCanvas.SCALE) - getAABB().getRadY();
}
TagsCanvas.CANVAS_WIDTH is the width of the canvas object. Height is the height of the canvas object. Size is the size of the player, and scale is the scale of the game (At the moment it's 2). getAABB().getRadX() returns the radius from the center of the player to the edge (The 'player' is a square box).
Now, the x works fine, but the Y part doesn't. It'll block the player from moving up off the map (The first statement), but it will let the player go about 20 points too far down. Any help would be appreciated!
What you can do is have it wraparound by using the Modulo operator (i.e. remainder after integer division).
Say you want to move 5 units:
Have a method:
public void move(int amt){
pos = (pos + amt) % TagsCanvas.CANVAS_WIDTH.
}
The Modulo operator makes sure that the value will never be equal to or greater than TagsCanvas.CANVAS_WIDTH.
Firstly, happy new year all.
Ive got a
int[] map = new int[2550];
and in that array I place the id of a block at that pos, so for example if the top left block in the map has a id of one
map[0] = 1
Now I'm trying to think how I would scroll my map now, as I render the map like so -
for(int y = 0 ;y < current.height;y++){
for(int x = 0 ; x < current.width;x++){
Block block = current.getBlock(x, y);
g.drawImage(block.texture, x * 30 , y * 30);
}
}
How would I scroll the map? to make it so for example the block that was at 0,0 is now at 0,1 or whatever. Thanks for the help.
Edit: Im using LWJGL and slick2d to do my rendering and stuff, so I cant use Swing or AWT.
Scrolling is simply drawing all your graphics with a variable offset. Let there be a current scroll position:
int scrollX, scrollY;
Update these variables (and redraw) whenever you want to scroll. In your drawing routine, change the loop like this:
for (int y = 0; y < current.height; y++) {
for (int x = 0; x < current.width; x++) {
Block block = current.getBlock(x, y);
g.drawImage(block.texture, x * 30 - scrollX, y * 30 - scrollY);
}
}
Now, that's basic scrolling, and that will work. However, if you are adding scrolling you probably are planning to have maps much larger than the screen. In that case, it is inefficient to draw the entire map every time. Therefore, instead of iterating over the entire map, you iterate over only the visible portion of the map, which is not too complex:
int startX = Math.max(scrollX / 30, 0);
int startY = Math.max(scrollY / 30, 0);
int limitX = Math.min((scrollX + windowWidth ) / 30 + 1, current.width );
int limitY = Math.min((scrollX + windowHeight) / 30 + 1, current.height);
for (int y = startY; y < limitY; y++) {
for (int x = startX; x < limitX; x++) {
Block block = current.getBlock(x, y);
g.drawImage(block.texture, x * 30 - scrollX, y * 30 - scrollY);
}
}
The min and max are to avoid trying to draw tiles outside the bounds of the map. Note that this is exactly the same loop as before, except that the loop bounds have been changed.
By the way, you should also put the size of your tiles in a variable, so that if you ever decide to resize your tiles, or add zooming, you don't have to change code all over the place:
static final int TILE_SIZE = 30;
...
g.drawImage(block.texture, x * TILE_SIZE - scrollX, y * TILE_SIZE - scrollY);