I have been wondering how I would go by making a health bar in libgdx/java. I am looking into a Shape Renderer thinking I can use a filled shape to create a health bar, though I am not sure on how to make an approach in that direction. On the other hand I have been looking into using scene2D and NinePatches to create a healthbar for the game. I have tried to use a NinePatch/Scene2D by looking up websites on google, though it seems when I add the code I always get an issue when I try to render it to my screen. So if anybody can help me create a functional health bar in libgdx using whatever method, I would be extremely thankful. Thank you.
I cannot post pictures yet, because I have not posted 10 posts. So here is the link http://gyazo.com/6650f3d820f31c99c3f8061ebed0bdec. Sorry
I don't have any experience with Scene2D and stages but here is how i would do a simple healthbar:
Create a rectangle and fill this with a color or texture.
When a player loses HP shorten that rectangle by the same percentage as the HP lost.
Create a basic Orthographic camera with the height/width of the screen. I usually call this viewportCam.
Below all the other draw logic you change the SpriteBatch too spriteBatch(viewportCam.Combined)
Within this spritebatch you draw the healthbar.
public void Draw()
{
spriteBatch(normalCam.combined);
spriteBatch.begin();
//Normal draw logic.
spriteBatch.end();
spriteBatch(viewportCam.combined);
spriteBatch.begin();
//Draw UI elements last so the will be drawn on top of the rest.
spriteBatch.end();
}
If you draw a slightly larger rectangle behind the healthbar you have yourself a border.
You can change color depending on how much percentage health is left.
Edit
Just came across this again and currently using another method. I a ninepatch from a 1 pixel wide red gradient. health = new NinePatch(gradient, 0, 0, 0, 0) this makes sure no artifacts occur while stretching it. From here I just calculate how long it needs to be and draw it.
width = currentHealth / totalHealth * totalBarWidth;
Now you can draw it anywhere you want.
health.draw(batch, 10, 10, width, gradient.getHeight);
If you want somekind of container for it you setup a ninepatch for it and draw it before the dynamic health in the background. So let's say the container is 2 bigger at top/bottom and 5 at left/right.
container = new NinePatch(containerRegion, 5, 5, 2, 2);
//Offset it by the dynamic bar, let's say the gradient is 4 high.
container.draw(batch, 5, 8, totalBarWidth + 10, 8);
health.draw(batch, 10, 10, width, 4);
I "hardcoded" the container 5 to the left and made it 10 longer so it fits horizontally. Vertically I lowered it by 2 and made it 8 high to fit the bar perfectly.
This is how you can do it ,implement logic your self
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
int i=0;
Texture texture,texture2;
#Override
public void create () {
batch = new SpriteBatch();
initTestObjects() ;
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0, 0, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(texture2,100,100,300,20);
batch.draw(texture,100,100,i,20);
if(i>300)
{
i=0;
}
i++;
batch.end();
}
private void initTestObjects() {
int width =1 ;
int height = 1;
Pixmap pixmap = createProceduralPixmap(width, height,0,1,0);
Pixmap pixmap2 = createProceduralPixmap(width, height,1,0,0);
texture = new Texture(pixmap);
texture2 = new Texture(pixmap2);
}
private Pixmap createProceduralPixmap (int width, int height,int r,int g,int b) {
Pixmap pixmap = new Pixmap(width, height, Format.RGBA8888);
pixmap.setColor(r, g, b, 1);
pixmap.fill();
return pixmap;
}
}
Related
I have a bug object that I want to move across the screen as soon as the game starts. The bug starts from the bottom left of the screen and is supposed to move to the top right and stop. What I have is the bug never really gets to the top right because the game screen(X and Y) size are not equal. How do I make the bug move to that position?
This is what I have.
public void create() {
spriteBatch = new SpriteBatch();
bug = new Sprite(new Texture("EnemyBug.png"));
bug.setSize(50, 85);
bug.setPosition(0,0);
}
public void render() {
xdeg++;
ydeg++;
Gdx.gl.glClearColor(0.7f, 0.7f, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
spriteBatch.begin();
bug.translate(xdeg, ydeg);
bug.draw(spriteBatch);
spriteBatch.end();
}
I'll assume that you know your window width (W) and height (H). First find the W / H ratio:
float ratio = screenWidth / screenHeight;
Then update your bug position accordingly:
bug.translate(ratio, 1);
This will make the sprite move through the screen diagonal.
I am a beginning Java Game Developer. For my first game, I'm making something along an advanced version of Minicraft
by Notch. However I have absolutely clue how to make a 2D Tile-Based World Generator.
Would anyone mind explaining how I would do this and maybe a link or two to some YouTube Videos?
I am using Eclipse EE for Java Developers.
Also I can't seem to resize my window to make the pixels larger. The image is 16 x 16 pixels, however I'd like to display it larger like minicraft (link above)
Here is the code for Skeleton.java (which is the framework ('Skeleton') of the game)`
package code;
import java.awt.Graphics;
public class Skeleton extends Loop{ //Should extend Applet?
public void init(){
Thread th= new Thread(this);
th.start();
offscreen = createImage(120,160); // 120, 160
d = offscreen.getGraphics();
addKeyListener(this); //15:43
}
public static final int HEIGHT = 120; //Original Height/Width= "120 x 160"
public static final int WIDTH = 160;
public static final String TITLE= "Test Game BETA";
public static final int SCALE = 3;
public void paint(Graphics g) {
d.clearRect(0, 0, 160, 120); //Error Here, Scale perhaps? -Disregard //0,0,160,120
d.drawImage(him, x, y, this); //12:17 http://www.youtube.com/watch?v=XmRD0PlAXEY
g.drawImage(offscreen, 0, 0, this);
}
public void update(Graphics g){
paint(g);
} //Finished at 15:33 ERROR w/ the circle -Fixed
}
//2D Tile Engine Must be Created
I am working on a project that is almost identical to this. The way I generate the worlds, I have a two-dimensional array of tiles, and a method that populates the array with tiles. The way the world is generated, I place a grass tile in each column, followed by a randomly determined number of dirt tiles, followed by stone tiles until the bottom of the world. Then, for the next column, I place a grass tile at a y-coordinate that is between -2 and +2 tiles from the previous grass's y-coordinate, and fill the rest of the column as before. Continue until you get to the end of the array.
To rescale images, I use this method
public void drawRezizedImage(Graphics g, Image image, int x, int y, int sizeX, int sizeY){
image.getScaledInstance(200, 200, Image.SCALE_SMOOTH);
g.drawImage(image, 0, 0, null);
}
This will simply draw a rescaled version of your, in this case 16 by 16px image.
Hope this was, what you were looking for.
I've been trying to create a game where there's a person falling. The size of my background texture is 480x3200, and I'm trying to create the game so that the camera keeps the person in the middle of the screen while falling down, and then stops at the bottom. But I can't get my background is extend beyond the screen it starts in, and then be able to see the rest of the image.
All of my code does right now is scale down the 480x3200 image down to fit onto my current screen (which I set to be 480x800), and then as the person falls, the background doesn't change.
Here's my WorldRenderer class where I've tried to do different things but every time, I can never get the person to see a different part of the image when it starts moving down.
public WorldRenderer(SpriteBatch b, World w) {
this.world = w;
this.cam = new OrthographicCamera(CAMERA_WIDTH, CAMERA_HEIGHT);
this.cam.position.set(CAMERA_WIDTH / 2, Person.position.y,0);
this.cam.setToOrtho(false, CAMERA_WIDTH, CAMERA_HEIGHT);
this.cam.update();
spriteBatch = b;
loadTextures();
}
public void render(float delta) {
person = world.getPerson();
moveCamera();
cam.update();
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.disableBlending();
spriteBatch.begin();
renderBackground();
spriteBatch.end();
spriteBatch.enableBlending();
spriteBatch.begin();
renderObjects();
spriteBatch.end();
}
private void moveCamera() {
cam.position.set(cam.position.x, Person.position.y, 0);
cam.update();
}
private void renderObjects() {
renderPerson();
renderBlocks();
renderPlatforms();
}
private void renderBackground() {
spriteBatch.draw(backgroundTexture, cam.position.x - CAMERA_WIDTH / 2, cam.position.y - CAMERA_HEIGHT / 2, CAMERA_WIDTH, CAMERA_HEIGHT);
}
}
Does anyone have any suggestions?
Edit:
Thanks, I changed the draw in renderBackground to
spriteBatch.draw(backgroundTexture,0,0, CAMERA_WIDTH, CAMERA_HEIGHT * 4); and it works now.
spriteBatch.draw(backgroundTexture, cam.position.x - CAMERA_WIDTH / 2,
cam.position.y - CAMERA_HEIGHT / 2, CAMERA_WIDTH, CAMERA_HEIGHT);
This code is drawing the background image relative to the camera's position. That's why changing the camera's position has no effect on the background image's position. Change it to something like this:
spriteBatch.draw(backgroundTexture,0,0);
Or u can simply use ParrallaxBackground and ParrallaxLayer class
This way u dont have to manage ur camera
Its done in an optimized manner in the mentioned class.
I want to draw some (filled) polygons with libGDX. It shoudn't be filled with a graphic/texture. I have only the vertices of the polygon (closed path) and tried to visualize with meshes but at some point this is not the best solution, I think.
My code for an rectangle is:
private Mesh mesh;
#Override
public void create() {
if (mesh == null) {
mesh = new Mesh(
true, 4, 0,
new VertexAttribute(Usage.Position, 3, "a_position")
);
mesh.setVertices(new float[] {
-0.5f, -0.5f, 0
0.5f, -0.5f, 0,
-0.5f, 0.5f, 0,
0.5f, 0.5f, 0
});
}
}
// ...
#Override
public void render() {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
mesh.render(GL10.GL_TRIANGLE_STRIP, 0, 4);
}
is there a function or something to draw filled polygons in an easier way?
Since recent updates of LibGDX, #Rus answer is using deprecated functions. However, I give him/her credits for the new updated version below:
PolygonSprite poly;
PolygonSpriteBatch polyBatch = new PolygonSpriteBatch(); // To assign at the beginning
Texture textureSolid;
// Creating the color filling (but textures would work the same way)
Pixmap pix = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pix.setColor(0xDEADBEFF); // DE is red, AD is green and BE is blue.
pix.fill();
textureSolid = new Texture(pix);
PolygonRegion polyReg = new PolygonRegion(new TextureRegion(textureSolid),
new float[] { // Four vertices
0, 0, // Vertex 0 3--2
100, 0, // Vertex 1 | /|
100, 100, // Vertex 2 |/ |
0, 100 // Vertex 3 0--1
}, new short[] {
0, 1, 2, // Two triangles using vertex indices.
0, 2, 3 // Take care of the counter-clockwise direction.
});
poly = new PolygonSprite(polyReg);
poly.setOrigin(a, b);
polyBatch = new PolygonSpriteBatch();
For good triangulating algorithms if your polygon is not convex, see the almost-linear earclipping algorithm from Toussaint (1991)
Efficient triangulation of simple polygons, Godfried Toussaint, 1991
Here is a libGDX example which draws a 2D concave polygon.
Define class members for PolygonSprite PolygonSpriteBatch
PolygonSprite poly;
PolygonSpriteBatch polyBatch;
Texture textureSolid;
Create instances, 1x1 size texture used with red pixel as workaround. An array of coordinates (x, y) is used for initialization of the polygon.
ctor() {
textureSolid = makeTextureBox(1, 0xFFFF0000, 0, 0);
float a = 100;
float b = 100;
PolygonRegion polyReg = new PolygonRegion(new TextureRegion(textureSolid),
new float[] {
a*0, b*0,
a*0, b*2,
a*3, b*2,
a*3, b*0,
a*2, b*0,
a*2, b*1,
a*1, b*1,
a*1, b*0,
});
poly = new PolygonSprite(polyReg);
poly.setOrigin(a, b);
polyBatch = new PolygonSpriteBatch();
}
Draw and rotate polygon
void draw() {
super.draw();
polyBatch.begin();
poly.draw(polyBatch);
polyBatch.end();
poly.rotate(1.1f);
}
I believe the ShapeRenderer class now has a polygon method for vertex defined polygons:
ShapeRenderer.polygon()
You can use the ShapeRenderer API to draw simple, solid-color shapes with Libgdx.
The code you've given is a reasonable way to draw solid color polygons too. Its much more flexible than ShapeRenderer, but is a good bit more complicated. You'll need to use glColor4f to set the color, or add a Usage.Color attribute to each vertex. See the SubMeshColorTest example for more details on the first approach and the MeshColorTexture example for details on the second approach.
Another option to think about is using sprite textures. If you're only interested in simple solid colors objects, you can use very simple 1x1 textures of a single color and let the system stretch that across the sprite. Much of Libgdx and the underlying hardware are really optimized for rendering textures, so you may find it easier to use even if you're not really taking advantage of the texture contents. (You can even use a 1x1 white texture, and then use a SpriteBatch with setColor and draw()
to draw different color rectangles easily.)
You can also mix and match the various approaches, too.
Use triangulation algorithm and then draw all triangles as GL_TRIANGLE_STRIP
http://www.personal.psu.edu/cxc11/AERSP560/DELAUNEY/13_Two_algorithms_Delauney.pdf
just wanted to share my related solution with you, namely for implementing and drawing a walkZone with scene2d. I basically had to put together the different suggestions of the others' posts:
1) The WalkZone:
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.PolygonRegion;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.EarClippingTriangulator;
import com.badlogic.gdx.math.Polygon;
import com.mygdx.game.MyGame;
public class WalkZone extends Polygon {
private PolygonRegion polygonRegion = null;
public WalkZone(float[] vertices) {
super(vertices);
if (MyGame.DEBUG) {
Pixmap pix = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
pix.setColor(0x00FF00AA);
pix.fill();
polygonRegion = new PolygonRegion(new TextureRegion(new Texture(pix)),
vertices, new EarClippingTriangulator().computeTriangles(vertices).toArray());
}
}
public PolygonRegion getPolygonRegion() {
return polygonRegion;
}
}
2) The Screen:
you can then add a listener in the desired Stage:
myStage.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
if (walkZone.contains(x, y)) player.walkTo(x, y);
// or even directly: player.addAction(moveTo ...
return super.touchDown(event, x, y, pointer, button);
}
});
3) The implementation:
The array passed to te WZ constructor is a set of x,y,x,y... points. If you put them counter-clockwise, it works (I didn't check the other way, nor know how it exactly works); for example this generates a 100x100 square:
yourScreen.walkZone = new WalkZone(new int[]{0, 0, 100, 0, 100, 100, 0, 100});
In my project it works like a charm, even with very intricated polygons. Hope it helps!!
Most answers suggest triangulation, which is fine, but you can also do it using the stencil buffer. It handles both convex and concave polygons. This may be a better solution if your polygon changes a lot, since otherwise you'd have to do triangulation every frame. Also, this solution properly handles self intersecting polygons, which EarClippingTriangulator does not.
FloatArray vertices = ... // The polygon x,y pairs.
Color color = ... // The color to draw the polygon.
ShapeRenderer shapes = ...
ImmediateModeRenderer renderer = shapes.getRenderer();
Gdx.gl.glClearStencil(0);
Gdx.gl.glClear(GL20.GL_STENCIL_BUFFER_BIT);
Gdx.gl.glEnable(GL20.GL_STENCIL_TEST);
Gdx.gl.glStencilFunc(GL20.GL_NEVER, 0, 1);
Gdx.gl.glStencilOp(GL20.GL_INVERT, GL20.GL_INVERT, GL20.GL_INVERT);
Gdx.gl.glColorMask(false, false, false, false);
renderer.begin(shapes.getProjectionMatrix(), GL20.GL_TRIANGLE_FAN);
renderer.vertex(vertices.get(0), vertices.get(1), 0);
for (int i = 2, n = vertices.size; i < n; i += 2)
renderer.vertex(vertices.get(i), vertices.get(i + 1), 0);
renderer.end();
Gdx.gl.glColorMask(true, true, true, true);
Gdx.gl.glStencilOp(GL20.GL_ZERO, GL20.GL_ZERO, GL20.GL_ZERO);
Gdx.gl.glStencilFunc(GL20.GL_EQUAL, 1, 1);
Gdx.gl.glEnable(GL20.GL_BLEND);
shapes.setColor(color);
shapes.begin(ShapeType.Filled);
shapes.rect(-9999999, -9999999, 9999999 * 2, 9999999 * 2);
shapes.end();
Gdx.gl.glDisable(GL20.GL_STENCIL_TEST);
To use the stencil buffer, you must specify the number of bits for the stencil buffer when your app starts. For example, here is how to do that using the LWJGL2 backend:
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.stencil = 8;
new LwjglApplication(new YourApp(), config);
For more information on this technique, try one of these links:
http://commaexcess.com/articles/7/concave-polygon-triangulation-shortcut
http://glprogramming.com/red/chapter14.html#name13
http://what-when-how.com/opengl-programming-guide/drawing-filled-concave-polygons-using-the-stencil-buffer-opengl-programming/
Very simple thing I'm trying to do here. I would like to have 2 images on top of one another. When i use my mouse event dragged and clicked on the top image, the area of the top level image selected will fade and make the lower image visible.
The way I see it, there are 2 ways I can do this:
I can make the top image Transparent over time (within the selected area)
or
I can delete the pixels individually in a spray can style fashion. Think the spray can tool from MS paint back in the day.
Heres some very basic code that i started which just lays the images on top of eachother
PImage sand;
PImage fossil;
void setup()
{
size(400,400);
background(255,255,0);
frameRate(30);
fossil = loadImage("foss.jpg");
sand = loadImage("sand.jpeg");
}
void draw()
{
image(fossil, 0, 0, width,height);
image(sand, 0, 0, width,height);
smooth();
if (mousePressed) {
fill(0);
tint(255,127); //the opacity function
} else {
fill(255);
}
}
So has anyone any comments on these 2 ways of creating opacity or perhaps there an easier way I've overlooked?
Perhaps I wasn't clear in my Spec as the 2 comments below are asking for clarification.
In its simplest terms, I have 2 images on top of each other. I would like to be able to make some modification to the top level image which would make the bottom image visible. However I need to make this modification to only part of the top level image.
I would like to know which is the better option. To make part of the top image become transparent using tint() or to delete the pixels from the top layer.
Then I will proceed with that approach. Any indication as to how to do it is also appreciated.
I hope this clears up any confusion.
If you simply want to crossfade between images, it can be with tint() as you code suggest. You were in fact quite close:
PImage sand;
PImage fossil;
void setup()
{
size(400, 400);
fossil = loadImage("CellNoise.jpg");
sand = loadImage("CellVoronoi.jpg");
}
void draw()
{
//tint from 255 to 0 for the top image
tint(255,map(mouseX,0,width,255,0));
image(fossil, 0, 0, width, height);
//tint from 0 to 255 for the bottom image - 'cross fade'
tint(255,map(mouseX,0,width,0,255));
image(sand, 0, 0, width, height);
}
For the "spray can style " erosion you can simply copy pixels from a source image into the destination image. It's up to you how you loop through pixels (how many, what order, etc.) to get the "spray" like effect you want, but here's a basic example of how to use the copy() function:
PImage sand,fossil;
int side = 40;//size of square 'brush'
void setup()
{
size(400, 400);
fossil = loadImage("CellNoise.jpg");
sand = loadImage("CellVoronoi.jpg");
}
void draw()
{
image(fossil, 0, 0, 400, 400);
if(mousePressed) {
for(int y = 0 ; y < side ; y++){
for(int x = 0; x < side; x++){
//copy pixel from 'bottom' image to the top one
//map sketch dimensions to sand/fossil an dimensions to copy from/to right coords
int srcX = (int)map(mouseX+x,0,width+side,0,sand.width);
int srcY = (int)map(mouseY+y,0,height+side,0,sand.height);
int dstX = (int)map(mouseX+x,0,width+side,0,fossil.width);
int dstY = (int)map(mouseY+y,0,height+side,0,fossil.height);
fossil.set(dstX, dstY, sand.get(srcX,srcY));
}
}
}
}
Note what I am simply looping to copy a square (40x40 in my case), but you can find other fun ways to loop and get different effects.
Have fun!