I am trying to create a simple board game using libGDX. Just that you have a rough idea of what I'm trying to do, imagine Bejeweled (though mine of course is not as complex).
The game involves a board with cells as squares. Depending on the level, this grid has a different number of cells, like 6x6 or 8x8. I also want to include some nice animation for switching the position of two neighboring cells (like in Bejeweled). Of course there also need to be some buttons on the screen.
My question is: What is the best way to do this? Shall I use a stage and then tables for the grid? Can I then still easily make an animation (using the Universal Tween Engine)? Or is it better to draw the Sprites individually? Or is there another completely different way of approaching this?
Thank you for your answers,
Cheers,
Tony
Sprite square = new Sprite(new Texture("texture"));
Render
float squareWidth = camera.viewportWidth / squaresOnWidth;
float squareHeight = camera.viewportHeight / squaresOnHeight;
square.setWidth(squareWidth);
square.setHeight(squareHeight);
batch.begin(); `
for(int y = 0; y < squaresOnHeight; y++){
for(int x = 0; x < squaresOnWidth; x++){
square.setX(x * squareWidth);
square.setY(y * squareHeight);
square.draw(batch);
}
}
batch.end();
This should output a grid of textures, not tested.
If you want to create smooth animation you should definitely look into UniveralTweenEngine, here's a demo of what it can do : http://www.aurelienribon.com/universal-tween-engine/gwt/demo.html
If you want the grid in buttons instead.
OrthoGraphicCamera camera = new OrthoGraphicCamera();
camera.setToOrtho(false, yourViewportWidth, yourViewportHeight);
camera.translate(xPos, yPos);
Stage stage = new Stage(your wanted stage width, your wanted stage height, false, batch);
stage.setCamera(camera);
for(int y = 0; y < buttonsOnHeight; y++){
for(int x = 0; x < buttonsOnWidth; x++){
stage.addActor(new TextButton("" + x + y * buttonsOnWidth, textButtonStyle);
}
}
The render
float buttonWidth = camera.viewportWidth / buttonsOnWidth;
float buttonHeight = camera.viewportHeight / buttonsOnHeight;
for(int y = 0; y < buttonsOnHeight; y++){
for(int x = 0; x < buttonsOnWidth; x++){
TextButton button = stage.getActors().get(x + y * buttonsOnWidth);
button.setX(x * buttonWidth);
button.setY(y * buttonHeight);
button.setWidth(buttonWidth);
button.setHeight(buttonHeight);
}
}
Then draw the stage, note that you should stop any batch that's currently running because stage has it's own batch.begin() and batch.end(). You could start your batch again after stage.draw();
stage.act(delta);
stage.draw();
To have a grid you could and should use camera:
OrthographicCamera cam = new OrthographicCamera(8,8);
You tell the camera to have a viewport of 8 x and 8 y.
The cameras (0,0) point is in the middle of the screen.
To have it at the left bottom you need to set its position to
cam.translate(camWidth / 2, camHeight / 2);
Now you can add your sqares at sqare.setX(0) for sqares on the bottom line or sqare.setY(3) to add it on the 4rd row from left to right. For the animations you could also use Actions, which allow you to add different movements to an actor and let him perform them over time. Example:
actor.addAction(Actions.parallel(Actions.moveTo(float x, float y, float duration), Actions.rotateTo(float rotation, float duration)));
With this code sample you tell your actor to move from his position to (x,y) in duration seconds and while he moves to this position he rotates from his current rotation to rotation in duration seconds.
Hope this helps
Related
I made a simple program that simulates cells in a grid with their own color and displays them as 4x4 pixels, at first i made it using java AWT and the performance was ok but i was curious about how LibGDX perform and it was about 5 times slower, am i doing something wrong or is LibGDX just that much slower? here is my rendering loop:
#Override
public void create () {
cam = new OrthographicCamera(width, height);
Gdx.graphics.setWindowedMode(width * scale, height * scale);
renderer = new ShapeRenderer();
inputs = new Inputs();
world = new World(width, height, 8);
Gdx.input.setInputProcessor(inputs);
}
Pixel thisPixel;
#Override
public void render () {
Gdx.gl.glClearColor(0, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
renderer.setProjectionMatrix(cam.combined);
renderer.begin(ShapeRenderer.ShapeType.Filled);
inputs.update();
for (int x = 0; x < width; x ++)
for (int y = 0; y < height; y ++) {
thisPixel = world.getPixel(x, y);
renderer.setColor(world.materials.colors[thisPixel.colorId]);
renderer.rect(x - width / 2 - 1, y - height / 2 - 1, 1, 1);
}
renderer.end();
System.out.println(Gdx.graphics.getFramesPerSecond());
}
AWT use canvas to draw which is a 2D surface. LibGDX use openGL which is for 3D rendering and you have to project it onto a 2D surface (renderer.setProjectionMatrix(cam.combined);)
Drawing rects and scaling are quite costly operations, so if you can find an other way to achieve what you want it might speed things up.
I've made a lighting engine which allows for shadows. It works on a grid system where each pixel has a light value stored as an integer in an array. Here is a demonstration of what it looks like:
The shadow and the actual pixel coloring works fine. The only problem is the unlit pixels further out in the circle, which for some reason makes a very interesting pattern(you may need to zoom into the image to see it). Here is the code which draws the light.
public void implementLighting(){
lightLevels = new int[Game.WIDTH*Game.HEIGHT];
//Resets the light level map to replace it with the new lighting
for(LightSource lightSource : lights) {
//Iterates through all light sources in the world
double circumference = (Math.PI * lightSource.getRadius() * 2),
segmentToDegrees = 360 / circumference, distanceToLighting = lightSource.getLightLevel() / lightSource.getRadius();
//Degrades in brightness further out
for (double i = 0; i < circumference; i++) {
//Draws a ray to every outer pixel of the light source's reach
double radians = Math.toRadians(i*segmentToDegrees),
sine = Math.sin(radians),
cosine = Math.cos(radians),
x = lightSource.getVector().getScrX() + cosine,
y = lightSource.getVector().getScrY() + sine,
nextLit = 0;
for (double j = 0; j < lightSource.getRadius(); j++) {
int lighting = (int)(distanceToLighting * (lightSource.getRadius() - j));
double pixelHeight = super.getPixelHeight((int) x, (int)y);
if((int)j==(int)nextLit) addLighting((int)x, (int)y, lighting);
//If light is projected to have hit the pixel
if(pixelHeight > 0) {
double slope = (lightSource.getEmittingHeight() - pixelHeight) / (0 - j);
nextLit = (-lightSource.getRadius()) / slope;
/*If something is blocking it
* Using heightmap and emitting height, project where next lit pixel will be
*/
}
else nextLit++;
//Advances the light by one pixel if nothing is blocking it
x += cosine;
y += sine;
}
}
}
lights = new ArrayList<>();
}
The algorithm i'm using should account for every pixel within the radius of the light source not blocked by an object, so i'm not sure why some of the outer pixels are missing.
Thanks.
EDIT: What I found is, the unlit pixels within the radius of the light source are actually just dimmer than the other ones. This is a consequence of the addLighting method not simply changing the lighting of a pixel, but adding it to the value that's already there. This means that the "unlit" are the ones only being added to once.
To test this hypothesis, I made a program that draws a circle in the same way it is done to generate lighting. Here is the code that draws the circle:
BufferedImage image = new BufferedImage(WIDTH, HEIGHT,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, WIDTH, HEIGHT);
double radius = 100,
x = (WIDTH-radius)/2,
y = (HEIGHT-radius)/2,
circumference = Math.PI*2*radius,
segmentToRadians = (360*Math.PI)/(circumference*180);
for(double i = 0; i < circumference; i++){
double radians = segmentToRadians*i,
cosine = Math.cos(radians),
sine = Math.sin(radians),
xPos = x + cosine,
yPos = y + sine;
for (int j = 0; j < radius; j++) {
if(xPos >= 0 && xPos < WIDTH && yPos >= 0 && yPos < HEIGHT) {
int rgb = image.getRGB((int) Math.round(xPos), (int) Math.round(yPos));
if (rgb == Color.white.getRGB()) image.setRGB((int) Math.round(xPos), (int) Math.round(yPos), 0);
else image.setRGB((int) Math.round(xPos), (int) Math.round(yPos), Color.red.getRGB());
}
xPos += cosine;
yPos += sine;
}
}
Here is the result:
The white pixels are pixels not colored
The black pixels are pixels colored once
The red pixels are pixels colored 2 or more times
So its actually even worse than I originally proposed. It's a combination of unlit pixels, and pixels lit multiple times.
You should iterate over real image pixels, not polar grid points.
So correct pixel-walking code might look as
for(int x = 0; x < WIDTH; ++x) {
for(int y = 0; y < HEIGHT; ++y) {
double distance = Math.hypot(x - xCenter, y - yCenter);
if(distance <= radius) {
image.setRGB(x, y, YOUR_CODE_HERE);
}
}
}
Of course this snippet can be optimized choosing good filling polygon instead of rectangle.
This can be solved by anti-aliasing.
Because you push float-coordinate information and compress it , some lossy sampling occur.
double x,y ------(snap)---> lightLevels[int ?][int ?]
To totally solve that problem, you have to draw transparent pixel (i.e. those that less lit) around that line with a correct light intensity. It is quite hard to calculate though. (see https://en.wikipedia.org/wiki/Spatial_anti-aliasing)
Workaround
An easier (but dirty) approach is to draw another transparent thicker line over the line you draw, and tune the intensity as needed.
Or just make your line thicker i.e. using bigger blurry point but less lit to compensate.
It should make the glitch less obvious.
(see algorithm at how do I create a line of arbitrary thickness using Bresenham?)
An even better approach is to change your drawing approach.
Drawing each line manually is very expensive.
You may draw a circle using 2D sprite.
However, it is not applicable if you really want the ray-cast like in this image : http://www.iforce2d.net/image/explosions-raycast1.png
Split graphic - gameplay
For best performance and appearance, you may prefer GPU to render instead, but use more rough algorithm to do ray-cast for the gameplay.
Nonetheless, it is a very complex topic. (e.g. http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/ )
Reference
Here are more information:
http://what-when-how.com/opengl-programming-guide/antialiasing-blending-antialiasing-fog-and-polygon-offset-opengl-programming/ (opengl-antialias with image)
DirectX11 Non-Solid wireframe (a related question about directx11 with image)
I am making a game in Android that requires a list of sprites to running from right to left so I try to flip the image using the code below.
It slows the game speed down so much, moves fast running to the right but slows down so much running to the left.
public void Draw(Canvas spriteBatch, int X, int Y, int imageIndex,int flip)
{
int drawY = (imageIndex / columns);
int drawX = imageIndex - drawY * columns;
int spriteX = drawX * spriteWidth;
int spriteY = drawY * spriteHeight;
Rect src = new Rect( spriteX, spriteY,spriteX + spriteWidth, spriteY + spriteHeight);
Rect dst = new Rect(X, Y, X + spriteWidth,Y + spriteHeight);
location.X = X;
location.Y = Y;
if(flip == 1)
{
//here image is flipped
spriteBatch.save();
spriteBatch.scale(-scaleX, scaleY, X, Y);
spriteBatch.drawBitmap(texture2D,src,dst, paint);
spriteBatch.restore();
//Use simple use this to flip image canvas.scale(-1, 1)
}
else if(flip == 0)
{
//draws sprite without flipping
spriteBatch.save();
spriteBatch.scale(scaleX, scaleY, X, Y);
spriteBatch.drawBitmap(texture2D,src,dst, paint);
spriteBatch.restore();
}
this.SetFrame(imageIndex);
}
I can flip using matrix but I can't draw a sprite using matrix.
Is there a way to draw sprite using matrix and would it make it faster?
matrix.reset();
matrix.setTranslate(location.X, location.Y);
matrix.setScale(-scaleX,scaleX);
matrix.postTranslate(location.X + texture2D.getWidth(), location.Y);
Or is there another way that is faster?
So I think that the matrix solution should will work perfectly the canvas object includes it's own built in matrix which if you manipulate will affect the output of all graphics after that point. So you just set the matrxi and then do the draw.
You're solution is okay but you're doing it wrong - rather do this part ONCE:
Create the left-ward facing sprite as you do at the beginning and then store it. Then EACH FRAME: Use this 'cached' copy of the inverted bitmap that you created.
A third solution (which I haven't tried but might work) is to manipulate the destination rectangle so that the left and right edges are swapped - the canvas docs say, "Draw the specified bitmap, scaling/translating automatically to fill the destination rectangle." - I suspect that this might include negative scaling to fit the space where the right edge is smaller than the left although the docs do not explicitly say so.
I am experimenting with game development in java. As of now, I can use the screen class to render to the Canvas of an image through pixel array. However, whenever I attempt to render to the canvas through the pixel array within the other class, it reads the pixels array's content. x y numbers and all but, does not render it to the canvas at all even though the other class extends the screen class (thus inheriting the pixels array and the x, y numbers).
What is causing this? How do I go about fixing it?
from the other class:
void origin(){
if(x <= ax && y <= ay)
pixels[ox + oy * width] = 0xff00ff;
}
From the screen class:
void waves(){
orga = new Organism(width, height);
for(y = 0; y < height; y++){
for(x = 0; x < width; x++){
Color wacol = new Color(0, 0, u);
int water = wacol.getRGB();
pixels[x + y * width] = water;
orga.origin();
}
}
}
Extending the class isn't enough, it has to be hooked up to the screen in the same way as the pixel array that works.
In order to build a tic-tac-toe game for testing, I have following routine. But problem is that I am getting too many events for just one touch. I suspect isTouched() returns all of down, up, and move. Is there any way to just get up event?
UPDATE: Resolved the issue by employing justTouched() instead.
#Override
public void render() {
// we update the game state so things move.
updateGame();
// First we clear the screen
GL10 gl = Gdx.graphics.getGL10();
gl.glViewport(0, 0, width, height);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// Next we update the camera and set the camera matrix
camera.update();
camera.apply(Gdx.gl10);
...
}
private void updateGame() {
// the delta time so we can do frame independant time based movement
float deltaTime = Gdx.graphics.getDeltaTime();
// Has the user touched the screen? then position the paddle
if (Gdx.input.isTouched() && !isProcess) {
// get the touch coordinates and translate them
// to the game coordinate system.
isProcess=true;
int width = Gdx.graphics.getWidth();
int height = Gdx.graphics.getHeight();
int offx=-width/2;
int offy=-height/2;
float x = Gdx.input.getX();
float y = Gdx.input.getY();
float touchX = 480 * (x
/ (float) width - 0.5f);
float touchY = 320 * (0.5f - y
/ (float) height);
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++)
{
if(touchX >= offx+i*width/3 && touchX < offx+(i+1)*width/3 &&
touchY >= offy+j*height/3 && touchY < offy+(j+1)*height/3)
{
if(isCurrentO)
data[i][j]=CellStatus.O;
else
data[i][j]=CellStatus.X;
isCurrentO=!isCurrentO;
break;
}
}
}
isProcess=false;
}
}
An alternative to using justTouched is to implement the InputProcessor interface, as it has a touchUp(x,y,pointer,button) which gives you greater control over the input. There are several classes that implement this or you can have your class implement it.
You can create a board for example (with hash map) and each object in your game wants to be clickable add itself to that board if an object was touched and was in board it will catch the event. If not it will not catch the event. So easy! :)