Good night friends.
I'm having trouble drawing a fixed point on the screen when the screen is rotated. I used the method "rotateAround" from the position of the player.
It seems to me. I have to rotate this fixed point also from the position of the player. I use this stretch learned here in stackoverflow.
public void rotate(Vector3 position, Vector3 centerPoint){
this.cosTemp = MathUtils.cosDeg(this.anguloAtual);
this.senTemp = MathUtils.sinDeg(this.anguloAtual);
this.xTemp = centerPoint.x + ((position.x - centerPoint.x) * this.cosTemp) - ((position.y - centerPoint.y) * this.senTemp);
this.yTemp = centerPoint.y + ((position.y - centerPoint.y) * this.cosTemp) + ((position.x - centerPoint.x) * this.senTemp);
position.set(this.xTemp, this.yTemp, 0);
}
In the drawing that the player on the screen. I used the position of the player, then called "camera.project" then the method "rotate". The fixed point appears, however it is not exactly fixed.
I used the example of a fixed point slightly ahead of the player.
public void meDesenhar(SpriteBatch spriteBatch) {
spriteBatch.begin();
this.spritePlayer.setPosition(this.positionPlayer.x - (this.spritePlayer.getWidth() / 2),
this.positionPlayer.y - this.spritePlayer.getHeight() / 2);
this.spritePlayer.draw(spriteBatch);
spriteBatch.end();
originPosition.set(positionPlayer, 0);
fixedPosition.set(positionPlayer.x, positionPlayer.y + 10, 0);
cameraTemp.project(fixedPosition);
cameraTemp.project(originPosition);
cameraManagerTemp.rotate(fixedPosition, originPosition);
Debugagem.drawPointInScreen(Color.BLUE, fixedPosition);
}
My questions:
1 - I am doing something wrong, or just it is a result of rounding? I realized when debugging. The position of the player changed a little every rotation after the "camera.project". Example position (540, 320) turned (539.99, 320.013)
2 - I tried using and enjoying the SpriteBatch the draw method to perform the rotation however, could not make the rotation from the player. I would arrive at the same result.
3 - Can I use two cameras? Each camera would be a layer. A camera at the map and the player would be. The other for fixed point. It's viable? I could not find any example that works with more than one camera at the same time. Anyone know any examples please. I'm not talking about huds or cameras to stage.
Video follows.
https://www.youtube.com/watch?v=1Vg8haN5ULE
Thank you.
It can be result of rounding because its moving a pixel.
You can calculate rotation from the player but its not necessary.
Of course you can use multiple cameras in your game and you should also in this case.
Its few screenshot from my old projects that i used multiple cameras
As you can see you can even use different type of cameras like ortho and perspective both 2D and 3D.
Just create new camera like first one and change projection matrix
camrotate = new OrthographicCamera(540, 960);
//...
camfixed = new OrthographicCamera(540, 960);
//...
And in render method
batch.setProjectionMatrix(camrotate.combined);
batch.begin();
//draw in camrotate now
//...
//...
batch.end();
batch.setProjectionMatrix(camfixed.combined);
batch.begin();
//draw fixed elements now
//...
//...
batch.end();
//add one more camera if you need
Edit:
Change projection matrix outside of batch.begin()/end() otherwise the current batch will flushed.
Related
I'm trying to implement linear interpolation and a fixed time step for my game loop. I'm using the libGDX engine and box2D. I'm attempting to find the amount the simulation moves my character's body during a world step like this:
old_pos = guyBody.getPosition();
world.step(STEP_TIME, VELOCITY_ITERATIONS, POSITION_ITERATIONS);
new_pos = guyBody.getPosition();
printLog(new_pos.x-old_pos.x);
This returns 0 each time. The simulation works fine, and the body definitely moves each step.
Additional code:
#Override
public void render(float delta) {
accumulator+=delta;
while (accumulator>=STEP_TIME){
accumulator-=STEP_TIME;
stepWorld();
}
alpha = accumulator/STEP_TIME;
update(delta);
//RENDER
}
private void stepWorld() {
old_pos = guyBody.getPosition();
old_angle = guyBody.getAngle() * MathUtils.radiansToDegrees;
world.step(STEP_TIME, VELOCITY_ITERATIONS, POSITION_ITERATIONS);
new_angle = guyBody.getAngle() * MathUtils.radiansToDegrees;
new_pos = guyBody.getPosition();
}
I'm attempting to use alpha to check how far I am in between physics steps so I can interpolate a Sprite's position.
Thanks!
Body's getPosition method is returning Vector reference - that means that you not copying it by value but only assign "pointer" on position object to old_pos/new_pos. However you are assigning it once before step and then after step all in all both variables keeps the same object with state after step already.
What you need to do is to copy position vector by value - to do this you can use Vector's cpy() method.
Your code should looks like
old_pos = guyBody.getPosition().cpy();
world.step(STEP_TIME, VELOCITY_ITERATIONS, POSITION_ITERATIONS);
new_pos = guyBody.getPosition().cpy();
printLog(new_pos.x-old_pos.x);
If you do not use y coordinate you should also consider keeping only x in float type variable to not copy whole object (however it should not really impact your performance).
While the accepted response does answer my question, I wanted to add some information I figured out while trying to get this to work that I wish I knew at the beginning of this.
If you're going to use a fixed timestep for your physics calculations (which you should), you should also interpolate(or extrapolate) a Sprite's position between physics steps. In my code, the screen is being rendered more often than the world is being stepped:
#Override
public void render(float delta) {
accumulator+=delta;
while (accumulator>=STEP_TIME){
accumulator-=STEP_TIME;
stepWorld();
}
alpha = accumulator/STEP_TIME;
update(delta);
//RENDER using alpha
}
To avoid a jittery rendering of moving objects, render Sprites or Textures at their positions, modified by alpha. Since alpha is the ratio of your accumulator to the step time, it will always be between 0 and 1.
You then need to find how much your body is moving during one step. This can be done with the accepted answer or using the body velocity:
newPos = oldPos + body.getLinearVelocity()*STEP_TIME*alpha
Then just render Sprite at the new position and you should see smooth movement with your fixed timestep at most frame rates.
I want to move some sprites from left to right with a constant slow speed. I have first tried RatioResolutionPolicy but I saw sprites were flickering a lot. Then I have changed resolutionpolicy to FixedResolutionPolicy, defined sprite textures as bitmap, scaled them and made sprites by these textures (for more detail: click here). This is better than first method but not completely good. I use setx() for moving sprites. When I change x positon for example by 2 pixels for each frame there is no problem. But for different devices that have different resolutions I must multiply 2 by a ratio. In this case sprites are flickering again, not much but it is annoying for me.
code for camera is below
#Override
public EngineOptions onCreateEngineOptions() {
WindowManager w = getWindowManager();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
Point size = new Point();
w.getDefaultDisplay().getSize(size);
V.CAMERA_WIDTH = size.x;
V.CAMERA_HEIGHT = size.y;
} else {
Display d = w.getDefaultDisplay();
V.CAMERA_WIDTH = d.getWidth();
V.CAMERA_HEIGHT = d.getHeight();
}
if (V.CAMERA_HEIGHT/V.CAMERA_WIDTH>480f/860f){
V.CAMERA_HEIGHT=V.CAMERA_WIDTH*480f/860f;
}
else {
V.CAMERA_WIDTH=V.CAMERA_HEIGHT*860f/480f;
}
V.ratio=V.CAMERA_HEIGHT/480f;
this.mCamera = new Camera(0, 0, V.CAMERA_WIDTH, V.CAMERA_HEIGHT);
final EngineOptions engineOptions = new EngineOptions(true,
ScreenOrientation.LANDSCAPE_FIXED, new FixedResolutionPolicy((int)V.CAMERA_WIDTH, (int)V.CAMERA_HEIGHT),
this.mCamera);
return engineOptions;
}
for moving sprites:
this.wallPosX -= this.speed;
this.setX(Math.round(this.wallPosX));
speed is a floating point varibale and it gets 4.4651165 for 1280x720 screen resolution. If I set it as an integer than there is no flickering, but this time sprite speed differs from device to device.
There are too many screen sizes and screen ratio's for android phones.
Use the Cropped Resolution Policy created by jgibbs. Follow Martin Varga's tutorial to get an understanding on how it works and how to implement it.
It works wonders.
Original from jgibbs
I recommend Martin's Tutorial
You shouldn't be worried about micro managing entities positional co-ordinates to suit every and any possible screen size.
I'm not sure this will fix the flickering though, that may be some other problem not related to your camera
I have noticed that this wasn't about Andengine, it was about opengl. Solution for this problem is this wonderful tool:
https://github.com/gemserk/imageprocessing
this is really basic but I can't figure out what's going wrong. Basically I'm trying to draw a circle around a certain area of one of my objects. I've initialised a ShapeRenderer in the constructor (called srDebugCircle) and have this for loop in the render() method to draw every object.
for (GameObject object : levels.get(LEVEL_INDEX)) {
if (object.getType() == ObjectType.SWINGING_SPIKES) {
object.draw(batch);
srDebugCircle.begin(ShapeType.Filled);
srDebugCircle.circle(object.getxPos() + object.getWidth()/2, object.getyPos(), object.getWidth()/2);
srDebugCircle.setColor(Color.BLACK);
srDebugCircle.end();
}
if (object.getType() == ObjectType.COIN && (Coin) object).isVisible()) {
object.draw();
}
...
}
The problem is I only see like 4 out of 15 objects when I add the code for the circle. When I remove it / comment it it works as usual - however, in both cases, I can never see a black filled circle.
I'm specifically talking about this part:
srDebugCircle.begin(ShapeType.Filled);
srDebugCircle.circle(object.getxPos() + object.getWidth()/2, object.getyPos(), object.getWidth()/2);
srDebugCircle.setColor(Color.BLACK);
srDebugCircle.end();
Can anybody see why I'm having this problem?
An alternative to Springrbua’s answer is to draw using Pixmaps instead of ShapeRenderer. Switching between SpriteBatch and ShaperRenderer is an expensive operation and Pixmaps don’t require ending the SpriteBatch. Pixmap offers fewer draw methods than ShapeRenderer, but it does include drawing a filled circle.
Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888);
pixmap.setColor(Color.BLACK);
pixmap.fillCircle(x, y, r);
Texture texture = new Texture(pixmap);
// render
batch.begin();
batch.draw(texture, x, y);
batch.end();
The problem is, that you have two Renderer/Batches running at the same time:
The SpriteBatch batch and the ShapeRenderer srDebugCircle.
This can result in strange behaivor.
To solve the problem, call end() for one Renderer/Batch before calling begin() for the other.
In your case it would look something like this:
object.draw(batch);
batch.end()
srDebugCircle.begin(ShapeType.Filled);
srDebugCircle.setColor(Color.BLACK); // Set Color before drawing
srDebugCircle.circle(object.getxPos() + object.getWidth()/2, object.getyPos(), object.getWidth()/2);
srDebugCircle.end();
Also note, that calling end() on a SpriteBatch calls flush() which should be called as rarely as possible. Therefore it might be a good idea to draw everything with the SpriteBatch and then draw all the ShapeRenderer things.
I've got a camera set up, and I can move with WASD and rotate the view with the mouse. But now comes the problem: I want to add physics to the camera/player, so that it "interacts" with my other jBullet objects. How do I do that? I thought about creating a RigidBody for the camera and storing the position there, so that jBullet can apply its physics to the camera. Then, when I need to change something (the position), I could simply change it in the RigidBody. But I didn't find any methods for editing the position.
Can you push me in the right direction or maybe give me an example source code?
I was asking the same question myself a few days ago. My solution was as Sierox said. To create a RigidBody of BoxShape and add that to the DynaicsWorld. To move the camera arund, apply force to its rigidbody. I have damping set to .999 for linear and 1 for angular to stop the camera when no force is applied, i.e. the player stops pressing the button.
I also use body.setAngularFactor(0); so the box isn't tumbling all over the place. Also set the mass really low as not to interfere too much with other objects, but still be able to jump on then and run into them, and otherwise be affected by them.
Remember to convert your x,y, and z coordinates to cartesian a plane so you move in the direction of the camera. i.e.
protected void setCartesian(){//set xyz to a standard plane
yrotrad = (float) (yrot / 180 * Math.PI);
xrotrad = (float) (xrot / 180 * Math.PI);
float pd = (float) (Math.PI/180);
x = (float) (-Math.cos(xrot*pd)*Math.sin(yrot*pd));
z = (float) (-Math.cos(xrot*pd)*Math.cos(yrot*pd));
//y = (float) Math.sin(xrot*pd);
}//..
public void forward(){// move forward from position in direction of camera
setCartesian();
x += (Math.sin(yrotrad))*spd;
z -= (Math.cos(yrotrad))*spd;
//y -= (Math.sin(xrotrad))*spd;
body.applyForce(new Vector3f(x,0,z),getThrow());
}//..
public Vector3f getThrow(){// get relative position of the camera
float nx=x,ny=y,nz=z;
float xrotrad, yrotrad;
yrotrad = (float) (yrot / 180 * Math.PI);
xrotrad = (float) (xrot / 180 * Math.PI);
nx += (Math.sin(yrotrad))*2;
nz -= (Math.cos(yrotrad))*2;
ny -= (Math.sin(xrotrad))*2;
return new Vector3f(nx,ny,nz);
}//..
to jump just use body.setLinearVelocity(new Vector3f(0,jumpHt,0)); and set jumpHt to whatever velocity you wish.
I use getThrow to return a vector for other objects i may be "throwing" on screen or carrying. I hope I answered your question and didn't throw in too much non-essential information.I'll try and find the source that gave me this idea. I believe it was on the Bullet forums.
------- EDIT ------
Sorry to have left that part out
once you have the rigid body functioning properly you just have to get it's coordinates and apply that to your camera for example:
float mat[] = new float[16];
Transform t = new Transform();
t = body.getWorldTransform(t);
t.origin.get(mat);
x = mat[0];
y = mat[1];
z = mat[2];
gl.glRotatef(xrot, 1, 0, 0); //rotate our camera on teh x-axis (left and right)
gl.glRotatef(yrot, 0, 1, 0); //rotate our camera on the y-axis (up and down)
gl.glTranslatef(-x, -y, -z); //translate the screen to the position of our camera
In my case I'm using OpenGL for graphics. xrot and yrot represent the pitch and yaw of your camera. the code above gets the world transform in the form of a matrix and for the purposes of the camera you need only to pull the x,y, and z coordinates then apply the transform.
from here, to move the camera, you can set the linear velocity of the rigid body to move the camera or apply force.
Before you read this answer I would like to mention that I have a problem with the solution stated in my answer. You can follow my question about that problem so that you can have the solution too if you use this answer.
So. First, you need to create a new BoxShape:
CollisionShape cameraHolder = new BoxShape(SIZE OF CAMERAHOLDER);
And add it to your world so that it interacts with all the other objects. Now you need to change all the methods about camera movement (not rotation) so that the methods move your cameraHolder but not your camera. Then set the position of your Camera to the position of the cameraHolder.
Again, if you have a problem where you can't move properly, you can check my question and wait for an answer. You also can find a better way of doing this.
If you have problems or did not understand something about the answer, please state it as a comment.
Few days ago I figured out how to do some scrolling in LibGdx. Now I'm triying to do something related. I want to repeat the background. My scrolling follows a ship (Is an s[ace ship game). In the background there is a space photo loaded as a Texture. When the ship reach the end of the backgorund, It keeps going and there's no background anymore. I have read about wrap but I don't really understand How It works. I did that:
px=new Pixmap(Gdx.files.internal("fondo.jpg"));
background=new Texture(px);
background.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
And then, in my render method
spriteBatch.begin();
spriteBatch.draw(background,0,0,500,50);
drawShip();
spriteBatch.end();
Of course It doesn't work, It only draws the background once. I don't know how make this wrap method work. Any help?
SOLUTION
I figured It out. It's not a nice code but It works.
First I declare two Textures with the same image
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
Also I declare two variables like this to specify the X value of the position of each bck
int posXBck1=0,posXBck2=0;
Then I use that in Render()
public void calculoPosicionFondos(){
posXBck2=posXBck1+ANCHODEFONDO;
if(cam.position.x>=posXBck2+cam.viewportWidth/2){
posXBck1=posXBck2;
}
}
Where:
ANCHODEFONDO is the width of my background
Cam is an OtrhoCam.
So I said that if the cam is in bck2 (wich means that you can't see bck1 anymore) It change positions, giving bck1 de position of bck2 and, in the next render loop, recalculating bck2
Then just paint both bck in your render mode.
Like Teitus said, do not load your texture multiple times, ever! Anyway, you where on the right track with the wrapper:
texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
Now you can just use the draw method with the source location. The source location is the area you choose to draw on the texture.
batch.draw(texture, x, y, srcX, srcY, srcWidth, srcHeight)
To scroll your texture from right to left all you have to do is increase srcX incrementally. So create a int that increments in the update/render method.
int sourceX = 0;
//render() method
//Increment the variable where to draw from on the image.
sourceX += 10;
//Simply draw it using that variable in the srcX.
batch.draw(YourTexture, 0, 0, sourceX, 0, screenWidth, screenHeight);
Because you are wrapping the texture it will wrap/loop and scroll indefinitely. There might be a issue with the sourceX int if the game runs for a very long time because a int can only hold 2147483647. It takes a while but you can fix it by subtracting the image width each time the number goes over the total image width.
Don't to this, please:
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
That will load your big background texture twice. That's a complete waste. If you want to keep your solution at least do:
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=bkg1;
Regarding the texture Wrapping. If your texture is 500px wide, and you draw a 500px sprite, you won't see any repetition. If you want it repeated 2 times, draw it 1000px wide with 0-2 texture coordinates.
I'm not sure how spriteBatch handles the call you posted, you could try that one, or may be use the overload that uses a texture region and set your region manually.
I see this is a pretty old question, but I think there is an easier way to accomplish background scrolling. Just use the Sprite class. Here is a snippet I use for layered background images that scroll from right to left.
public class LevelLayer
{
public float speedScalar = 1;
private List<Sprite> backgroundSprites = new ArrayList<Sprite>();
public LevelLayer()
{
}
public void addSpriteLayer(Texture texture, float startingPointX, float y, int repeats)
{
for (int k = 0; k < repeats; k++)
{
Sprite s = new Sprite(texture);
s.setX(startingPointX + (k*texture.getWidth()));
s.setY(y);
backgroundSprites.add(s);
}
}
public void render(SpriteBatch spriteBatch, float speed)
{
for (Sprite s : backgroundSprites)
{
float delta = s.getX() - (speed * speedScalar);
s.setX(delta);
s.draw(spriteBatch);
}
}
}
Then you can use the same texture or series of textures like so:
someLayer.addSpriteLayer(sideWalkTexture1, 0, 0, 15);
someLayer.addSpriteLayer(sideWalkTexture2, 15 * sideWalkTexture1.getWidth(), 0, 7);
I change background repeating sections randomly in code and make new ones or reset existing sets when they go off screen. All the layers go to a pool and get pulled randomly when a new one is needed.
SOLUTION
I figured It out. It's not a nice code but It works.
First I declare two Textures with the same image
bck1=new Texture(Gdx.files.internal("fondo.jpg"));
bck2=new Texture(Gdx.files.internal("fondo.jpg"));
Also I declare two variables like this to specify the X value of the position of each bck
int posXBck1=0,posXBck2=0;
Then I use that in Render()
public void calculoPosicionFondos(){
posXBck2=posXBck1+ANCHODEFONDO;
if(cam.position.x>=posXBck2+cam.viewportWidth/2){
posXBck1=posXBck2;
}
}
Where:
ANCHODEFONDO is the width of my background
Cam is an OtrhoCam.
So I said that if the cam is in bck2 (wich means that you can't see bck1 anymore) It change positions, giving bck1 de position of bck2 and, in the next render loop, recalculating bck2
Then just draw both bck in your render()