So I am creating a sprite and drawing it to the screen using a different class.
I now want to scale it to be the same aspect ratio/size on each screen.
I have tried doing that by using this code:
public Player(Vector2 position, float width, float height, float rotation, float speed)
{
super(speed, rotation, width, height, position);
}
public void update()
{
width = Gdx.graphics.getWidth() / 10;
height = Gdx.graphics.getHeight() / 10;
}
But this doesn't work, it does nothing.
I have also tried setting the width and height to a static value for example 100 by 100. But this does not work either.
Thank you for any help! :)
Edit: adding base and derived classes:
Here's the code for the Entity class:
public abstract class Entity {
public void setPosition(Vector2 position) {
this.position = position;
}
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
public Rectangle getBounds() {
return bounds;
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
}
Here's the code for the MoveEntity class:
public MoveEntity(float speed, float rotation,
float width, float height,
Vector2 position) {
super(position, width, height);
this.speed = speed;
this.rotation = rotation;
vel = new Vector2(0, 0);
}
public Vector2 getVel() {
return vel;
}
public void setVel(Vector2 target) {
this.vel = target;
}
public float getRotation() {
return rotation;
}
public void setRotation(float r) {
..............///
maybe it do not speak English, but you talk about a sprite and I do not see him any site, anyway.
assuming this is the sprite to which you refer -> spr_player
You can do this in several ways but basing on this line of code that you publish
Variable class. (for test):
float width = Gdx.graphics.getWidth() / 10;
float height = Gdx.graphics.getHeight() / 10;
Try to use this:
sb.draw(spr_player, p.getPosition().x, p.getPosition().y
width, height);
this is the funtion in the Class SpriteBatch:
public void draw (Texture texture, float x, float y,
float width, float height)
also you could use, setSize in the Sprite class, somewhere before render.
spr_player.setSize(width, height);
this is the funtion in the Class Sprite:
public void setSize (float width, float height)
if the size will not change during the game maybe, you can call the setSize, in method created or show, or in the constructor call this way, if the result you want:
Sprite spr_player = new Sprite (your_texture, width, height);
this is the funtion in the Class Sprite:
public Sprite (Texture texture, int srcWidth, int srcHeight)
Related
I am using this tool:
https://github.com/codenameone/flamingo-svg-transcoder
you can read more about it here:
https://www.codenameone.com/blog/flamingo-svg-transcoder.html#commento-login-box-container
I used it to convert a svg file and this is the result:
/**
* This class has been automatically generated using
* Flamingo SVG transcoder.
*/
public class MyImageFromSVGSubset extends com.codename1.ui.Image implements Painter {
private int width, height;
private Transform t = Transform.makeIdentity(), t2 = Transform.makeIdentity();
public MyImageFromSVGSubset() {
super(null);
width = getOrigWidth();
height = getOrigHeight();
}
public MyImageFromSVGSubset(int width, int height) {
super(null);
this.width = width;
this.height = height;
fixAspectRatio();
}
#Override
public int getWidth() {
return width;
}
#Override
public int getHeight() {
return height;
}
#Override
public void scale(int width, int height) {
this.width = width;
this.height = height;
fixAspectRatio();
}
#Override
public MyImageFromSVGSubset scaled(int width, int height) {
MyImageFromSVGSubset f = new MyImageFromSVGSubset(width, height);
f.fixAspectRatio();
return f;
}
public Image toImage() {
Image i = Image.createImage(width, height, 0);
Graphics g = i.getGraphics();
drawImage(g, null, 0, 0, width, height);
return i;
}
private void fixAspectRatio() {
if(width == -1) {
float ar = ((float)getOrigWidth()) / ((float)getOrigHeight());
width = Math.round(((float)height) * ar);
}
if (height == -1) {
float ar = ((float)getOrigHeight()) / ((float)getOrigWidth());
height = Math.round(((float)width) * ar);
}
}
#Override
public Image fill(int width, int height) {
return new MyImageFromSVGSubset(width, height);
}
#Override
public Image applyMask(Object mask) {
return new MyImageFromSVGSubset(width, height);
}
#Override
public boolean isAnimation() {
return true;
}
#Override
public boolean requiresDrawImage() {
return true;
}
#Override
protected void drawImage(Graphics g, Object nativeGraphics, int x, int y) {
drawImage(g, nativeGraphics, x, y, width, height);
}
#Override
protected void drawImage(Graphics g, Object nativeGraphics, int x, int y, int w, int h) {
g.getTransform(t);
t2.setTransform(t);
float hRatio = ((float) w) / ((float) getOrigWidth());
float vRatio = ((float) h) / ((float) getOrigHeight());
t2.translate(x + g.getTranslateX(), y + g.getTranslateY());
t2.scale(hRatio, vRatio);
g.setTransform(t2);
paint(g);
g.setTransform(t);
}
private static void paint(Graphics g) {
int origAlpha = g.getAlpha();
Stroke baseStroke;
Shape shape;
g.setAntiAliased(true);
g.setAntiAliasedText(true);
/*Composite origComposite = g.getComposite();
if (origComposite instanceof AlphaComposite) {
AlphaComposite origAlphaComposite = (AlphaComposite)origComposite;
if (origAlphaComposite.getRule() == AlphaComposite.SRC_OVER) {
origAlpha = origAlphaComposite.getAlpha();
}
}
*/
java.util.LinkedList<Transform> transformations = new java.util.LinkedList<Transform>();
//
transformations.push(g.getTransform());
g.transform(new AffineTransform(3.7795277f, 0, 0, 3.7795277f, 0, 0).toTransform());
// _0
// _0_0
// _0_0_0
shape = new Rectangle2D(0.008569182828068733, 0.0054579987190663815, 6.3905863761901855, 6.390747547149658);
g.setColor(0xffffff);
g.fillShape(shape);
// _0_0_1
shape = new GeneralPath();
((GeneralPath) shape).moveTo(5.0011573, 1.454892);
((GeneralPath) shape).curveTo(4.914109, 1.454892, 4.8439946, 1.526065, 4.8439946, 1.6128483);
...
...
//very long sequence of graphical instructions that corresponds to the actual drawing
...
...
((GeneralPath) shape).closePath();
g.fillShape(shape);
g.setTransform(transformations.pop()); // _0
g.setAlpha(origAlpha);
}
/**
* Returns the X of the bounding box of the original SVG image.
*
* #return The X of the bounding box of the original SVG image.
*/
public static int getOrigX() {
return 1;
}
/**
* Returns the Y of the bounding box of the original SVG image.
*
* #return The Y of the bounding box of the original SVG image.
*/
public static int getOrigY() {
return 1;
}
/**
* Returns the width of the bounding box of the original SVG image.
*
* #return The width of the bounding box of the original SVG image.
*/
public static int getOrigWidth() {
return 24;
}
/**
* Returns the height of the bounding box of the original SVG image.
*
* #return The height of the bounding box of the original SVG image.
*/
public static int getOrigHeight() {
return 24;
}
#Override
public void paint(Graphics g, Rectangle rect) {
drawImage(g, null, rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
}
It's Java code to be used in my application (Codename One) but it doesn't work for me.
I put the following code into a working layout:
button.setIcon(new MyImageFromSVGSubset(256,256));
The image is present because it occupies the right space (256x256) but nothing is drawn.
What is the mistake?
I am trying to move actor on stage from point to point by actions and it is not working, i have tried for hours and it just not working, i will be glad for help..
I have searched by the internet for codes and all i tried didn't worked, i really dont understand what is wrong with this code, it is basically the same as a working one on a tutorial in the internet
the actor class:
public class Player extends Actor {
float x,y;
float screenWidth,screenHeight;
private Sprite sprite;
Texture image;
float width,height;
public Player(Texture image,float x, float y,float width,float height, float screenWidth, float screenHeight)
{
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.screenWidth = screenWidth;
this.screenHeight = screenHeight;
this.image = image;
sprite = new Sprite(image, 0, 0, image.getWidth(), image.getHeight());
sprite.setPosition(x, y);
}
#Override
public float getX() {
return x;
}
#Override
public void setX(float x) {
this.x = x;
}
#Override
public float getY() {
return y;
}
#Override
public void setY(float y) {
this.y = y;
}
#Override
public float getWidth() {
return width;
}
#Override
public void setWidth(float width) {
this.width = width;
}
#Override
public float getHeight() {
return height;
}
#Override
public void setHeight(float height) {
this.height = height;
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
public void draw (Batch batch, float parentAlpha) {
batch.draw(sprite,x,y,width,height);
}
}
and the main class:
player = new Player(playerTexture,screenWidth/2,screenHeight-200,playerTexture.getWidth(),playerTexture.getHeight(),screenWidth,screenHeight);
MoveToAction action = new MoveToAction();
action.setPosition(300f,0f);
action.setDuration(10f);
player.addAction(action);
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(orthographicCamera.combined);
batch.begin();
// batch.draw(playerTexture,10,10,10,10);
batch.end();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw(); //this will call the batch to draw the sprite
}
Actor already has x, y, width, and height fields. Since you created your own, you have hidden those parameters.
The source of your problem is that you failed to override setPosition() to use your fields. So the move action calls that and changes the fields that you have hidden and when you draw it, you are using your own fields that have not been changed.
Don't hide fields. It is very error-prone. You should delete the fields I mentioned above, along with all your overrides of getters and setters.
Here's a rule of thumb for OOP in general: if you are overriding any getter or setter without calling the super method, you are probably breaking something.
Unrelated, but you should be using TextureRegion instead of Sprite. A Sprite is a TextureRegion with additional parameters for size and position. Since those features are also in Actor, it is redundant and error-prone to use Sprite.
Is there some easy way to create a Button in LibGDX that contains several polygon drawables inside.
For example when the simple Button can be pictured like:
and advanced expected button like that:
And in my case following conditions must be met:
The Object must extends Button class.
Separated polygons (circle and triangle in pic) must have one common behavior - same up, down, hover styles, same click listeners ect. (for example when user hover circle the triangle and circle change color to green)
Actually it must have the absolutely same behavior as button with one polygon, just imagine that circle and triangle is one polygon, instead of separated ones.
The one way I figured out is to extend PolygonRegionDrawable, but to make it drawn correctly I need to override almost all methods from Drawable and TransformDrawable, is there any easier way to do that?
Maybe there can be found some DrawableGroup or something like that?
I dont think theres an easy way to make this work, here are some options.
Button is a Table, you can add stuff to it.
Button button = new Button(skin);
Image img = new Image(...); // insert polygon 1 here
img.setPostion(...); // offset so its in correct position in the button
button.addActor(img);
// add more stuff
Sadly this doesnt handle various state changes, like over etc. You would need to keep track of the added stuff and change them as button changes.
Other option is to make the polygons into single image.
Thats quite tricky, you would draw them into FrameBufferObject in correct places and make a textures out of that. Then use that texture for Drawable for the button style. Reapet for each state you want to handle. Packing them into and atlas would be optimal for perfomace reasons. A ton of texture switches is not great.
In order to reach such functionality I have implemented two additional classes that may assume a list of Drawables to draw it like only one.
So I just mention it here, I hope it may be useful for people who want to implement the same behavior.
An abstract class that assumes list of drawables and related coordinates in format:
[drawable1X, drawable1Y, drawable2X, drawable2Y, ..., drawableNX, drawableNY]
BulkBaseDrawable:
abstract class BulkBaseDrawable implements Drawable {
Array<Drawable> drawables;
private float leftWidth, rightWidth, topHeight, bottomHeight, minWidth, minHeight, leftX, bottomY, rightX, topY;
BulkBaseDrawable(Drawable[] drawables,
float... vertices) {
this.infos = new Array<>(drawables.length);
init(drawables, vertices);
}
#Override
public float getLeftWidth() {
return leftWidth;
}
#Override
public void setLeftWidth(float leftWidth) {
this.leftWidth = leftWidth;
}
#Override
public float getRightWidth() {
return rightWidth;
}
#Override
public void setRightWidth(float rightWidth) {
this.rightWidth = rightWidth;
}
#Override
public float getTopHeight() {
return topHeight;
}
#Override
public void setTopHeight(float topHeight) {
this.topHeight = topHeight;
}
#Override
public float getBottomHeight() {
return bottomHeight;
}
#Override
public void setBottomHeight(float bottomHeight) {
this.bottomHeight = bottomHeight;
}
#Override
public float getMinWidth() {
return minWidth;
}
#Override
public void setMinWidth(float minWidth) {
this.minWidth = minWidth;
}
#Override
public float getMinHeight() {
return minHeight;
}
#Override
public void setMinHeight(float minHeight) {
this.minHeight = minHeight;
}
void init(Drawable[] drawables, float[] vertices) {
initInfo(drawables, vertices);
initEdges();
initSize();
}
private void initInfo(Drawable[] drawables, float[] vertices) {
int i = 0;
for (Drawable drawable : drawables) {
infos.add(Info.builder()
.x(vertices[i])
.y(vertices[i + 1])
.width(drawable.getMinWidth())
.height(drawable.getMinHeight())
.drawable(drawable)
.build());
i += 2;
}
}
private void initSize() {
minHeight = topY - bottomY;
minWidth = rightX - leftX;
}
private void initEdges() {
topY = Float.MIN_VALUE;
rightX = Float.MIN_VALUE;
bottomY = Float.MAX_VALUE;
leftX = Float.MAX_VALUE;
int topI = 0;
int rightI = 0;
int bottomI = 0;
int leftI = 0;
for (int i = 0; i < infos.size; i++) {
Info info = infos.get(i);
if (info.y + info.height > topY) {
topY = info.y + info.height;
topI = i;
}
if (info.x + info.width > rightX) {
rightX = info.x + info.width;
rightI = i;
}
if (info.y < bottomY) {
bottomY = info.y;
bottomI = i;
}
if (info.x < leftX) {
leftX = info.x;
leftI = i;
}
}
Drawable top = infos.get(topI).drawable;
Drawable right = infos.get(rightI).drawable;
Drawable bottom = infos.get(bottomI).drawable;
Drawable left = infos.get(leftI).drawable;
leftWidth = left.getLeftWidth();
rightWidth = right.getRightWidth();
topHeight = top.getTopHeight();
bottomHeight = bottom.getBottomHeight();
}
static class Info {
float x, y, width, height;
Drawable drawable;
static InfoBuilder builder() {
return new InfoBuilder();
}
static class InfoBuilder {
float x, y, width, height;
Drawable drawable;
InfoBuilder x(float x) {
this.x = x;
return this;
}
InfoBuilder y(float y) {
this.y = y;
return this;
}
InfoBuilder width(float width) {
this.width = width;
return this;
}
InfoBuilder height(float height) {
this.height = height;
return this;
}
InfoBuilder drawable(Drawable drawable) {
this.drawable = drawable;
return this;
}
Info build() {
return new Info(x, y, width, height, drawable);
}
}
public Info(float x, float y, float width, float height, Drawable drawable) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.drawable = drawable;
}
}
}
And actually implementation BulkRegionDrawable:
public class BulkRegionDrawable extends BulkBaseDrawable {
public BulkRegionDrawable(Drawable[] drawables, float[] vertices) {
super(drawables, vertices);
}
#Override
public void draw(Batch batch,
float x,
float y,
float width,
float height) {
for (int i = 0; i < infos.size; i++) {
Info info = infos.get(i);
float yK = info.height / getMinHeight();
float xK = info.width / getMinWidth();
info.drawable.draw(
batch,
x + (info.x * width) / getMinWidth(),
y + (info.y * height) / getMinHeight(),
width * xK,
height * yK);
}
}
}
Here is my Core project :
public class GameClass extends Game {
public static int screenWidth, screenHeight;
public static CustomScreen currentScreen;
public static PlayScreen playScreen;
#Override
public void create () {
screenWidth = Gdx.graphics.getWidth();
screenHeight = Gdx.graphics.getHeight();
CustomScreen.initialize();
playScreen = new PlayScreen(this);
SetScreen(playScreen);
}
public void SetScreen(CustomScreen screen) {
currentScreen = screen;
setScreen(currentScreen);
}
}
public abstract class CustomScreen implements Screen {
GameClass game;
static BitmapFont font;
static SpriteBatch batcher;
static OrthographicCamera cam;
public CustomScreen(GameClass game) {
this.game = game;
}
public static void initialize() {
cam = new OrthographicCamera();
cam.setToOrtho(true, GameClass.screenWidth, GameClass.screenHeight);
batcher = new SpriteBatch();
batcher.setProjectionMatrix(cam.combined);
font = new BitmapFont();
font.setScale(4f, -4f);
}
public void Clear() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
#Override
public abstract void render(float delta);
}
public class PlayScreen extends CustomScreen {
public static final int speed = 300;
public ArrayList<Entity> entityList;
Random rand = new Random();
float timer = rand.nextInt(2) + rand.nextFloat();
public PlayScreen(GameClass game) {
super(game);
entityList = new ArrayList<Entity>();
}
void update(float delta) {
timer -= delta;
if (timer <= 0) {
entityList.add(new Enemy(GameClass.screenWidth, rand.nextInt(GameClass.screenHeight - Enemy.Height)));
timer += rand.nextInt(2) + rand.nextFloat() + 1/2;
}
for (int i = entityList.size(); i > 0; --i)
entityList.get(i-1).update(delta);
}
#Override
public void render(float delta) {
Clear();
update(delta);
batcher.begin();
for (int i = 0; i < entityList.size(); ++i) {
entityList.get(i).Display(batcher);
}
if (entityList.size() > 1)
System.out.println(entityList.get(1).posX - entityList.get(0).posX);
batcher.end();
}
}
public abstract class Entity {
protected Sprite sprite;
public int posX, posY, width, height;
public Entity(int posX, int posY, int width, int height) {
this.posX = posX;
this.posY = posY;
this.width = width;
this.height = height;
}
public abstract void update(float delta);
public void Display(SpriteBatch batcher) {
batcher.draw(sprite, posX, posY, width, height);
}
}
public class Enemy extends Entity {
static Sprite texture = new Sprite(new Texture(Gdx.files.internal("enemy.png")));
public static int Width = 300, Height = 200;
public Enemy(int posX, int posY) {
super(posX, posY, Width, Height);
this.sprite = Enemy.texture;
}
#Override
public void update(float delta, int i) {
posX -= delta * PlayScreen.speed;
if (posX + width < 0) {
GameClass.playScreen.entityList.remove(this);
}
}
}
In PlayScreen, enemies keep spawning randomly, and they move from the right of the screen to the left, at a constant speed (final int 300). But when they reach the left edge of the screen (when posX <= 0), they slow down, for an unknown reason. The thing is, I didn't program anything to happen when an enemy reaches the edge of the screen. (I programmed them to disappear when they are completely outside of the screen, when posX + width <= 0, but it has nothing to do with my problem, since even when I remove this, they keep slowing down when reaching the edge of the screen).
It happends with both the desktop and the android projects, so this definitely comes from the Core project.
I have no idea why this happens, this is really, really awkward.
Here is a couple picture to show you what happens.
http://i.stack.imgur.com/DrOSH.png
http://i.stack.imgur.com/Zjtju.png
We can see that the two enemies are closer to each other on the second picture than on the first one.
You can set PlayScreen.speed to 100 instead of 300, it will be even more noticeable.
And if you set it to a low enough value, like 20, enemies will not just slow down, they will basically stop moving.
I'm lost and have no idea how to fix this problem. If you have any, please feel free to share it.
I fixed it. The problem was that Enemy.posX was an int instead of a float.
I'm not quite certain but I'd guess that your calculations in the Enemy class involving delta get rounded (since PlayScreen.Speed is an integer).
Having a low enough PlayScreen.Speed or a low enough delta will result in delta * PlayScreen.Speed being 0.something which will get cut off to 0 when converting to an integer, resulting in posX never changing.
I usually use floats for all calculations involving positions (e.g. posX and posY and so on...) so that this cutting off doesn't happen until something gets drawn on the screen (since pixels are always integers). This produces more accurate results and solves a lot of problems around movement on the screen.
Don't know if it was a very specific title, but I have already asked this question but has gone dead.
I am trying to execute paintComponent() so I can draw rectangles, triangles and more with the class being a JComponent.
Here is my code so far:
public class Design extends JComponent {
private static final long serialVersionUID = 1L;
private List<ShapeWrapper> shapesDraw = new ArrayList<ShapeWrapper>();
private List<ShapeWrapper> shapesFill = new ArrayList<ShapeWrapper>();
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
int screenWidth = gd.getDisplayMode().getWidth();
int screenHeight = gd.getDisplayMode().getHeight();
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for(ShapeWrapper s : shapesDraw){
g2d.setColor(s.color);
g2d.draw(s.shape);
}
for(ShapeWrapper s : shapesFill){
g2d.setColor(s.color);
g2d.fill(s.shape);
}
}
public void drawRect(int xPos, int yPos, int width, int height) {
shapesDraw.add(new Rectangle(xPos, yPos, width, height));
repaint();
}
public void fillRect(int xPos, int yPos, int width, int height) {
shapesFill.add(new Rectangle(xPos, yPos, width, height));
repaint();
}
public void drawTriangle(int leftX, int topX, int rightX, int leftY, int topY, int rightY) {
shapesDraw.add(new Polygon(
new int[]{leftX, topX, rightX},
new int[]{leftY, topY, rightY},
3));
repaint();
}
public void fillTriangle(int leftX, int topX, int rightX, int leftY, int topY, int rightY) {
shapesFill.add(new Polygon(
new int[]{leftX, topX, rightX},
new int[]{leftY, topY, rightY},
3));
repaint();
}
public Dimension getPreferredSize() {
return new Dimension(getWidth(), getHeight());
}
public int getWidth() {
return screenWidth;
}
public int getHeight() {
return screenHeight;
}
}
class ShapeWrapper {
Color color;
Shape shape;
public ShapeWrapper(Color color , Shape shape){
this.color = color;
this.shape = shape;
}
}
As shown above, everything works perfectly fine, except for being able to choose a colour.
I want to be able to define the rectangles and triangles with their respective positions and lengths but also want to add a colour with it.
But I get an error.
The error says:
The method add(ShapeWrapper) in the type List< ShapeWrapper > is not applicable for the arguments (Rectangle)
And:
The method add(ShapeWrapper) in the type List< ShapeWrapper > is not applicable for the arguments (Polygon)
Please help! I am so stressed trying to figure this out as it is blocking me from doing many things.
The answer is pretty basic...Shape is not a type of ShapeWrapper, therefore it can't be added to a List decalred as List<ShapeWrapper>
What you should be doing instead of
shapesDraw.add(new Rectangle(xPos, yPos, width, height));
is something more like...
shapesDraw.add(new ShapeWrapper(Color.BLACK, new Rectangle(xPos, yPos, width, height)));
The same goes for your ...Triangle methods. You need to wrap the resulting Polygon in a ShapeWrapper before trying to add it to the List