Slick tiledmap render explanation - java

Im trying to render a map for a game I am making using tiled map from the slick class but im having a lot of trouble understanding the difference between the parameters x and y. Below is a googled explanation but im not understanding it
public void render(int x,
int y,
int sx,
int sy,
int width,
int height)
Render a section of the tile map
Parameters:
x - The x location to render at
y - The y location to render at
sx - The x tile location to start rendering
sy - The y tile location to start rendering
width - The width of the section to render (in tiles)
height - The height of the secton to render (in tiles)
My game consists of a car and a camera locked onto it which will follow the car around on the map. The map starts to render as the car move. Could someone give me an explanation on how x and y and sx and sy applies to this.

The render function takes a rectangular area of tiles and draws them onto a rectangular area of pixels on the screen.
x and y specify the top left corner of the pixel rectangle
sx and sy specify the top left corner of the tile rectangle
width and height specify the area of the tile rectangle

Related

Why is a Pixmap circle off by 1?

I'm trying to draw a circle using Pixmap. To make the problem clearer, I'm filling the entire Pixmap area in white, then drawing the circle in a different color. Here is the code that I feel should work.
I'm setting the width/height of the Pixmap to twice the size of the radius of the circle.
Then I'm drawing a circle in the middle of the Pixmap at (radius, radius).
public static Texture circle(int radius, Color color) {
Pixmap pixmap = new Pixmap(radius * 2, radius * 2, Pixmap.Format.RGBA4444);
pixmap.setColor(Color.WHITE);
pixmap.fill();
pixmap.setColor(color);
pixmap.fillCircle(radius, radius, radius);
Texture texture = new Texture(pixmap);
pixmap.dispose();
}
Unfortunately, the Pixmap cuts off the circle on the right and bottom sides. For example:
If I increase the size of the Pixmap by 1 in both the width and height, then it looks fine:
I can just arbitrarily add an extra pixel but I'd like to understand why this is necessary. Why does setting the radius of the circle to X result in a diameter that is actually X + 1?
To get the result you want, the location of the circle's center would have to fall between two pixels, so that there are a similar number of whole pixels on either side of that location. My guess is that the Pixmap code defines a pixel's location to mean the center of a pixel. So the point (radius, radius) is closer to the right edge than the left, and (radius-1, radius-1) is closer to the left edge than the right. With this definition of location, the center of your circle should be at location (radius-.5, radius-.5).
If you have to put the center of the circle in the middle of a pixel, then it makes sense that you'd use the location (radius, radius) for the circle and that you'd need the width and height of the Pixmap to be (2*radius + 1, 2*radius+1). This way, there are the same number of pixels, radius+.5 pixels, on either side of the center of the circle. You might at that point want to draw a circle of radius radius + .5 if the library will take that.
Because it draws a circle centered on a pixel, not between pixels.
So the actual radius of the circle drawn is one more than passed in, a circle with radius 1 is drawn as (numbers are coordinates in this example):
012
0 X
1XCX
2 X
This technically has a radius of 1.5, but now it's centered on a pixel (C).
I am guessing this is to allow you to place it accurately, as if it actually had a radius of 2, you wouldn't be able to place the center on a pixel.

How to calculate a point out of an angle and a distance?

I searched and implemented things from this forum, it doesn't come out right.
What I'm trying to achieve is to calculate a spawnPoint for player bullets relative to his position and rotation.
The spawnPoint should be and his X + his width (the player is set to point to the right by default) and y + height/2 (to spawn from his center on the Y axis).
This is what I got from this forum:
this.bulletSpawn.x = (float)(this.position.x + this.width/2 + this.width * Math.cos(rotation));
this.bulletSpawn.y = (float)(this.position.y + this.height/2 + this.height/2 * Math.sin(rotation));
The rotation is in Radians. The this is the Player class.
Images showing what I expect to happen:
Original Position
Expected Behaviour
The red dot is the spawnPoint I'm trying to calculate knowing the player position and rotation.
The player Sprite is what rotates, and it rotates related to his center x and y, which is done with a lib, i do not have these variables. The entire arrow would be the player , the arrow direction is where the player is pointing at, and the red dot would be the bulletSpawn point (or the expected one)
Using the code I posted, the bullets seem to be spawning from somewhere else. Even at the beggining they have an offset and when I rotate the player the spawnPoint seems to be relative to a different origin than what I'm expecting.
This is the bullet position code:
position.x = holder.bulletSpawn.x - (float)(this.width/2 * holder.rotation);
position.y = holder.bulletSpawn.y - (float)(this.height/2 * holder.rotation);
This is inside the Bullet class. The position variable is a Vector2 of bullet, and holder is the player instance. This code is merely to give an offset for the bullet to spawn at the center of its own size
I added some fixes related to the comments, but the bullets still have a tiny offset that looks wrong at certain angles.
Basically the distance i want to get is the width of the player, and his center y which is height/2.
Let's initial position is X0, Y0, rotation is about center point CX, CY, and rotation angle is Theta. So new position after rotation is:
NX = CX + (X0-CX) * Cos(Theta) - (Y0-CY) * Sin(Theta)
NY = CY + (X0-CX) * Sin(Theta) + (Y0-CY) * Cos(Theta)
This equations describe affine transformation of rotation of arbitrary point about center point, and affine matrix is combination of translation, rotation, and back translation matrices.
About center CX, CY - you wrote
it rotates related to his x and y origin at his bottom left
About initial point coordinate - for bullet it seems to be
X + Width, Y + Height/2
Swift extension:
extension CGSize {
static func offsetFrom(angle:CGFloat, distance:CGFloat) -> CGSize {
let rad = angle * CGFloat.pi / 180
return CGSize(width: sin(rad) * distance, height: cos(rad) * distance)
}
}

How to rotate sprite via draw method

I have not found answer for this question anywhere, so let's go.
What i expect:
I want to render rocket. Rocket is flying from given start point with evaluated angle. I'm evaluating angle like this:
getVelocity().angle() - 90f
My problem is to calibrate rocket position on top of the rocket. Image below shows how should it work:
In the top picture is how libgdx render not rotated texture region. In the bottom picture is what i expect: I want to move and rotate texture region with given angle to have (x,y) coordinate on the top of rocket.
What i have:
I tired to write method to draw sprite how i expect but i failed. I think it is caused due to fact that i don't understand documentation of this method.
Following manual:
void com.badlogic.gdx.graphics.g2d.SpriteBatch.draw(TextureRegion region, float x, float y, float originX, float originY, float width, float height, float scaleX, float scaleY, float rotation)
Draws a rectangle with the bottom left corner at x,y and stretching the region to cover the given width and height. The rectangle is offset by originX, originY relative to the origin. Scale specifies the scaling factor by which the rectangle should be scaled around originX, originY. Rotation specifies the angle of counter clockwise rotation of the rectangle around originX, originY.
My code:
public static void drawRotatedTex(SpriteBatch pmRenderer, TextureRegion pmTex, float pmPosX, float pmPosY, float pmAngle)
{
pmRenderer.begin();
pmRenderer.draw(
pmTex, pmPosX, pmPosY, -pmTex.getRegionWidth()/2, pmTex.getRegionHeight(), pmTex.getRegionWidth(), pmTex.getRegionHeight(), 1f, 1f, pmAngle);
pmRenderer.end();
}
Results:
It is moment of collision. As we can see coordinates are offset in relation to rocket.
I don't ask about full solution. For me will be sufficient if someone explain me (on drawing or something) like this method works.
EDIT
Moderation suggested that this question is duplicate of:
libgdx: Rotate a texture when drawing it with spritebatch
I read this topic, but it is not my solution. I know how to rotate my sprite by i don't have idea why coordinates of rocket are offset in relation to rocket top.
EDIT
Invocation of my drawRotatedTex from rocket class:
#Override
public void render(Renderer pmRenderer, float pmX, float pmY) {
SpriteBatch lvSpritebatch = pmRenderer.getSpriteBatch();
Sprite lvSprite = null;
if(mIsExploding)
{
if((lvSprite = mExplosion.getTexture()) != null)
{
lvSpritebatch.begin();
lvSpritebatch.draw(lvSprite, pmX + lvSprite.getWidth()/2, pmY - lvSprite.getHeight()/2);
lvSpritebatch.end();
}
}
else
{
lvSprite = mAnimation.getTexture();
RendererTools.drawRotatedTex(lvSpritebatch,lvSprite,pmX,pmY,getVelocity().angle() - 90f);
}
}
It is not very clear what you are asking, if it's only about moving the origin you would not need that much text. Anyway, I will take a shot at it.
If you want to accomplish what you have in your picture you setup your sprite like this:
sprite.setOrigin(s.getWidth()/2, s.getHeight()); //Centers sprite on top of image.
If I now rotate it in the draw method it rotates around the top center.
sprite.rotate(5);
sprite.draw(batch);
Despite being rotated around the center top of itself it remains position remains the same. If I would set the origin far away from the image and rotate it then the image would travel very far but the position remains the same. Still if you would move it's position 10 pixels to the right the image (wherever it may be) will be moved to the right.
Hope this helps.

draw ellipse using center point (not upper left corner)

I try to find a solution for drawing ellipses based on the center point, not the upper left corner as it is specified in the constructor of Ellipse2D.Double. As seen in the picture the ellipses should have the same center point and scale, is that somehow possible?
Thanks in advance for your help.
If (x,y) is the center you want to use and you can only specify the upper left corner, then use the following:
private Ellipse2D getEllipseFromCenter(double x, double y, double width, double height)
{
double newX = x - width / 2.0;
double newY = y - height / 2.0;
Ellipse2D ellipse = new Ellipse2D.Double(newX, newY, width, height);
return ellipse;
}
If called with the center point and the width and height, this will "transform" your center point to the upper left corner and create an Ellipse2D which is located just as you want it to be.
The 'Upper' coordinate is misleading , it only works assuming y >=0 ( which works fine for a screen referential , bur not if you use the primitive with y <0 , for instance calculating object collisions )
With the usual math referential , where y<0 is possible , up is at the bottom
so it lacks a general definition not to get confused
The exact definition is that x and y are the min coordinates of the bounding rectangle.
It can be 'up' or 'down' ( relatively to your screen i suppose ) depending on the y axis orientation and y coordinate sign

Java Slick2d - How to translate mouse coordinates to world coordinates

I am translating in my main class' render. How do I get the mouse position based on the translation?
public void render(GameContainer gc, Graphics g)
throws SlickException
{
float centerX = 800/2;
float centerY = 600/2;
g.translate(centerX, centerY);
g.translate(-player.playerX, -player.playerY);
gen.render(g);
player.render(g);
}
playerX = 800 /2 - sprite.getWidth();
playerY = 600 /2 - sprite.getHeight();
I update the player position on keydown by .2f * delta
Picture to help with explanation
i92.photobucket.com/albums/l22/occ31191/Untitled-4.png
World coordinates = camera position + mouse position
Camera position is calculated/explained in my answer to this question: Slick2D and JBox2D. How to draw
You're making a tile-based game, where each tile seems to have the same size. For this case, you don't need a generalized unprojection.
Imagine the complete map. The viewport shows only a portion of it; somewhere you need to store the (x,y) offets of the viewport into the complete map. Since the mouse coordinates are relative to the viewport, you need to add this offset to the mouse coordinates. Now, you can easily get the tile coordinates by using modulo operations on the shifted mouse coordinates with the tile's width and height.
Effectively, this is a coordinate transformation of window coordinates to tile coordinates.

Categories