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.
Related
I want to draw a lot of sprites so I wrote this code in render method:
for(int i=0;i<100;i++)
{
spriteBlocchi[i] = new Sprite(blocco);
batch.draw(spriteBlocchi[i],xBlocco,50,100,200);
xBlocco = xBlocco + 0.1f;
}
spriteBlocchiis a Sprite array. I wrote this because in this way all 100 sprites are drawn by the render method, but it doesn't work. It draws only a sprite and I don't know why, in fact I created an array of sprites. This cycle is always called in render, so all the blocks should be drawn...what's the problem?
When ran, the program displays a 3D sphere rendered in a P3D environment in the PGraphics object 'g', which is shown by taking the rendered PGraphics object and displaying it through the image() method in the main graphics context, which happens to be P2D.
The purpose of the program is to show how window size doesn't always correlate with render size. If you play an old Widows98 game in full screen, the game most likely will be rendered at 480p no matter what, so taking it into full screen just decreases the pixels per inch, plus making the image appear blurry. Which is fine, since fullscreen at 480p is preferred over windowed mode ( esp. if you're on 4K X_X )
the mouse's y position in the window changes the 3d camera's field of view, and the x position changes the rendering resolution of the P3D context used to display the sphere. Additionally, the P3D context is drawn in the main (P2D) context through the image() method, and is 'forcefully'. displayed at the size of the window. So if the P3D render resolution is smaller than the window, then it will start to look blurry and more pixelated, and if the render resolution is larger, you get a strange sharpening effect.
Now, my program works fine as it is, but. Another purpose of the program is shadowed by this issue, it's how the 'crispness' of the sphere fades as the render resolution decreases. You might say that it's clearly shown, but what I'm looking for is an image where there is no "anti-alias" effect going on. I want the image to preserve the pixels as the resolution gets smaller, so you can see the actual shape of the sphere at say, 50 x 50 pixels.
The noSmooth() method doesn't seem to work, and before you tell me to just do
g.loadPixels();
and then do a double for loop to draw the raw pixels to the 2d context. No, it's sloppy. I know that there must be some reason why this blurring is going on. I'm hoping that it's the image() method and that I should be using a different method or I should add another method before it to remove image blurring.
PGraphics g;
void setup(){
size(1000,1000,P2D);
frameRate(1000);
noSmooth();
}
void draw(){
background(200);
float res = map(mouseX,0,width,0.75,128);
if (res==0) {
res=1;
}
g = createGraphics((int)(width/res),(int)(height/res),P3D);
g.noSmooth(); // is this thing working?????
float cameraZ = ((height/2.0) / tan(PI*60.0/360.0));
g.beginDraw();
g.perspective(radians(map(mouseY,0,height,0.1,160)), width/height, cameraZ/10.0, cameraZ*10.0);
g.camera(g.width/2.0, g.height/2.0, (height/2.0) / tan(PI*30.0 / 180.0), g.width/2.0, g.height/2.0, 0, 0, 1, 0);
g.background(200);
g.translate(g.width/2 ,g.height/2);
g.sphere(100);
g.endDraw();
image(g, 0, 0, width, height); // this is where it all comes together
text("rendering resolution: "+g.width+" x "+g.height,0,14);
text("fps: "+frameRate,0,14*2);
}
Replace g.noSmooth() with ((PGraphicsOpenGL)g).textureSampling(2);
Credits go to Vallentin as I oddly enough had the same question with the P3D renderer
(Edit: This solution fixes the problem in the default renderer, but the OP is using the P2D renderer. The solution should be similar, so if somebody knows how to change the image interpolation mode in opengl, that's the answer.)
This is not really caused by anti-aliasing. It's caused by image scaling.
Also, it's much easier to help if you provide a MCVE, like this one:
PGraphics buffer;
void setup() {
size(1000, 1000);
buffer = createGraphics(100, 100);
buffer.noSmooth();
buffer.beginDraw();
buffer.background(255);
buffer.line(0, 0, width, height);
buffer.endDraw();
}
void draw() {
background(0);
image(buffer, 0, 0, mouseX, mouseY);
}
This code exhibits the same problem, but it's much easier to understand and work with.
Anyway, tracing through Processing's code, we can see that the image() function eventually calls the imageImpl() function in the PGraphics class here.
This function then draws your image using this code:
beginShape(QUADS);
texture(img);
vertex(x1, y1, u1, v1);
vertex(x1, y2, u1, v2);
vertex(x2, y2, u2, v2);
vertex(x2, y1, u2, v1);
endShape();
The endShape() function is then implemented in the renderer, specifically the PGraphicsJava2D class, which calls the drawShape() function here:
protected void drawShape(Shape s) {
if (fillGradient) {
g2.setPaint(fillGradientObject);
g2.fill(s);
} else if (fill) {
g2.setColor(fillColorObject);
g2.fill(s);
}
if (strokeGradient) {
g2.setPaint(strokeGradientObject);
g2.draw(s);
} else if (stroke) {
g2.setColor(strokeColorObject);
g2.draw(s);
}
}
Finally, that shows us that the Graphics2D.fill() function is being called, which is what actually draws your function.
The "problem" is that Graphics2D.fill() is scaling your image using an algorithm that causes some blurriness. We can consult the Java API and Google to figure out how to fix that though.
Specifically, this tutorial shows you how to set various rendering hints to change the scaling algorithm. We can use that in Processing like this:
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import processing.awt.PGraphicsJava2D;
PGraphics buffer;
void setup() {
size(1000, 1000);
buffer = createGraphics(100, 100);
buffer.noSmooth();
buffer.beginDraw();
buffer.background(255);
buffer.line(0, 0, width, height);
buffer.endDraw();
}
void draw() {
if (mousePressed) {
Graphics2D g2d = ((PGraphicsJava2D)g).g2;
g2d.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
}
background(0);
image(buffer, 0, 0, mouseX, mouseY);
}
First, we import the classes we're going to need. Then we get to the Graphics2D instance in the renderer, and finally we call its setRenderingHint() function. I wrapped it in an if(mousePressed) so you could easily see the difference. When you click the mouse, interpolation is set to nearest neighbor, and you no longer see the blurriness.
Also notice that my code uses the g variable that's inherited from the PApplet superclass, so you would have to change your g variable so it's no longer hiding it.
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.
Ok I have this code
#Override
public void render() {
// do not update game world when paused
if (!paused) {
// Update game world by the time that has passed
// since last render frame
worldController.update(Gdx.graphics.getDeltaTime());
}
// Sets the clear screen color to: Cornflower Blue
Gdx.gl.glClearColor(0x64/255.0f, 0x95/255.0f, 0xed/255.0f,
0xff/255.0f);
// Clears the screen
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// Render game world to screen
worldRenderer.render();
}
And it draws a light blue background onto the screen. I am attempting to create a gradient that goes from a dark blue at the top, to a light blue towards the bottom. Is there a simple way to do this? I'm new to Libgdx, and OpenGL so i'm trying to learn from a book but I can't seem to find the answer to this one. I've heard of drawing a big square and having the vertices different colors, but I'm unsure of how to do this.
In libGDX, the ShapeRenderer object contains a drawRect() method that takes arguments for its position and size as well as four colors. Those colors are converted to a 4-corners gradient. If you want a vertical gradient, just make the top corners one color and the bottom corners another color. Something like this:
shapeRenderer.filledRect(x, y, width, height, lightBlue, lightBlue, darkBlue, darkBlue);
From the API for ShapeRenderer:
The 4 color parameters specify the color for the bottom left, bottom right, top right and top left corner of the rectangle, allowing you to create gradients.
It seems ShapeRenderer.filledRect method has been removed in late libGDX versions. Now the way to do this is as follows:
shapeRenderer.set(ShapeRenderer.ShapeType.Filled);
shapeRenderer.rect(
x,
y,
width,
height,
Color.DARK_GRAY,
Color.DARK_GRAY,
Color.LIGHT_GRAY,
Color.LIGHT_GRAY
);
The parameters for rect method work in the same way as those in filledRect used to do, like in Kevin Workman answer.
There are some further details worth bearing in mind before comitting to ShapeRenderer. I for one will be sticking with stretching and tinting Texture.
private Color topCol = new Color(0xd0000000);
private Color btmCol = new Color(0xd0000000);
#Override
public void render(float delta) {
...
batch.end(); //Must end your "regular" batch first.
myRect.setColor(Color.YELLOW); // Must be called, I don't see yellow, but nice to know.
myRect.begin(ShapeRenderer.ShapeType.Filled); //Everyone else was saying call `set`.
//Exception informed me I needed `begin`. Adding `set` after was a NOP.
myRect.rect(
10, 400,
//WORLD_H - 300, // WORLD_H assumed 1920. But ShapeRenderer uses actual pixels.
420,
300,
btmCol, btmCol, topCol, topCol
);
myRect.end();
I was hoping to change transparency dynamically as player health declines. The btmCol and topCol had no effect on transparency, hence I'll stick to Textures. Translating pixel space is no biggie, but this is much more than the proferred single or double line above.
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()