I am trying to use de Image Button on LIBGDX to create a button based on two images.
Using add to second image, works fine, but have one problem.
The images are of different sizes.
Note: I am testing with the same picture to see the result
Is there a way to correct this? Using some scale to the images?
levelsTexture = new Texture(Gdx.files.internal("level1.png"));
levels = new TextureRegion(levelsTexture).split(TILE_WIDTH, TILE_HEIGHT);
ImageButton levels_image = new ImageButton(new TextureRegionDrawable(new
TextureRegion(levels[0][0])));
levels_image.add(new Image (levels[0][0]));
stage.addActor(levels_image);
levels_image.setScale(2f);
The problem:
ImageButton is an extension of the Table class and typically the ImageButton images are set as the background. Using the "add" method for the second image like you did might work kind of, but it behaves differently than setting the background and it also might not be what you want if you want the the second image to also change when you click the button.
The easiest way to add two images to a single ImageButton would be to simply combine the two images in Photoshop (or equivalent) and use that single image on the ImageButton.
The more advanced (and more flexible) method would be to combine the two images programmatically and use this as the background for your ImageButton. This can be done by creating a custom class which extends BaseDrawable and have it take two Images in the constructor. If you want your images stacked on top of each other, set the minHeight of your custom drawable class to be the combined height of your two images. Then override the draw method and draw your two images on top of each other like this:
#Override
public void draw(Batch batch, float x, float y, float width, float height){
img1.getDrawable().draw(batch, x, y, img1.getWidth(), img1.getHeight());
img2.getDrawable().draw(batch, x, y+img1.getHeight(), img2.getWidth(), img2.getHeight());
}
}
The ImageButton takes a Drawable in its constructor, so you can pass this object right into the button when you create it and both of your Images should appear in the button and they will be treated as one.
I've done something similar to make a background for a table using multiple Images and this method works great.
I wrote my own SpriteButton class in which I implement this method for scaling my textures.
private Dimension getScaledDimension(Dimension imgSize, Dimension boundary) {
int original_width = imgSize.width;
int original_height = imgSize.height;
int bound_width = boundary.width;
int bound_height = boundary.height;
int new_width = original_width;
int new_height = original_height;
// first check if we need to scale width
if (original_width > bound_width) {
//scale width to fit
new_width = bound_width;
//scale height to maintain aspect ratio
new_height = (new_width * original_height) / original_width;
}
// then check if we need to scale even with the new height
if (new_height > bound_height) {
//scale height to fit instead
new_height = bound_height;
//scale width to maintain aspect ratio
new_width = (new_height * original_width) / original_height;
}
return new Dimension(new_width, new_height);
}
Then finally you draw the texture with the output dimension as as size to draw.
sb.begin();
sb.draw(this.texture2, this.x, this.y, dim_size_new.width, dim_size_new.height);
sb.end();
So you could technically draw the second image to the size of the the first image, if the first image size is correct.
Your implementation will look different from mine but you should be able to figure it out form here on out.
Related
I hate to ask such a generic question but I'm really stuck and super hoping someone can help me along the way. Here is the situation:
I'm making the GUI for a mobile app, portrait mode. I'm using canvas scalers to scale my canvasses with a reference width of 1080. This means I effectively don't know the height of my screen space.
What I want to create is a menu with a variable amount of items. The menu must be anchored to the bottom (with an offset margin) and grow upwards. So far I've been able to manage this using VerticalLayoutGroup and anchoring the rect transform to the bottom.
But my last requirement is that if the content would grow too big, a scrollbar would appear. The definition of the content being too big is: if it would extend the (unknown) screen height ( minus the offset margin of course). I hope the following image illustrates this much clearer:
I have a unity project here: https://ufile.io/v31br
Did you give a try to scrollView? here it is: https://unity3d.com/learn/tutorials/topics/user-interface-ui/scroll-view
You can use your vertical layout inside it and you will probably want to deactivate horizontal scroll and delete the horizontal slider.
Via script you can check its rectTransform height and compare it to your container's size, when reached maxHeight you can start managing your item's sizes
I assume you use the ScrollRect component as it is the right component to use in your case.
You can check the screen height with the Screen.height property.
Once you know the screen height you can compare it with your rect height and toggle the scrollbar with the ScrollRect.vertical property. You may have to change the ScrollRect.verticalScrollbarVisibility to permanent in order to make it work for you.
The answer Dave posted was close, but the problem is that the scrollview doesn't expand. I fixed it eventually by stretching the scrollview and resizing the parent manually as items are added. I set the anchors to the maximum size and adjust the sizeDelta.
public class MenuScript : MonoBehaviour
{
public int MenuItemCount;
public GameObject MenuItemPrefab;
public Transform MenuItemParent;
private RectTransform _rectTransform;
void Start()
{
_rectTransform = GetComponent<RectTransform>();
for (var i = 0; i <= MenuItemCount; i++)
{
GameObject instance = Instantiate(MenuItemPrefab, MenuItemParent, false);
instance.GetComponent<Text>().text = instance.name = "Item " + i;
float size = instance.transform.GetComponent<RectTransform>().sizeDelta.y;
TryExpandBy(size + 10);
}
}
private void TryExpandBy(float size)
{
var deltaY = _rectTransform.sizeDelta.y + size;
if (deltaY > 0) deltaY = 0;
_rectTransform.sizeDelta = new Vector2(_rectTransform.sizeDelta.x, deltaY);
}
}
I want to display UI logo images in their aspect ratio but in proper size that fit within its container. Already all logo images as per aspect ratio but few are too big or small compare to requirements.
At present this kind of thing happening:
Here is the code that I am using:
private void ShowGamePlayLogoViewed ()
{
for (int i = 0; i < DataCollection.companyDetailsList.Count; i++) {
Company company = DataCollection.companyDetailsList [i];
if (company.ViewedCounter > 0) {
GameObject companyItemObj = Instantiate (companyItemPref, gridViewContainer) as GameObject;
CompanyItem companyItem = companyItemObj.GetComponent<CompanyItem> ();
companyItem.companyId = company.CompanyId;
companyItem.UpdateCompanyLogo (company.CompanyLogo);
companyItem.UpdateCompanyName (company.CompanyName);
}
}
}
public void UpdateCompanyLogo (Sprite logoSprite)
{
logoImage.sprite = logoSprite;
logoImage.SetNativeSize ();
}
As you are seeing, logos overlapping the container. I want to display properly them in their respective containers also in aspect ratio too.
Let me clarify one more thing: all logos loaded from web server and they all are dynamic at a time, based on server data it will appear in mobile screen.
I have found solution through Unity Forum and I want to say thanks to #Hosnkobf for reply.
Here is the exact reply that worked for me properly:
adjust the image game object inside unity so that it has the height you are looking for. also adjust the anchors so that it scales with different resolutions properly.
Add an "AspectRatioFitter" component to the object. Make it "Height controls width".
Instead of logoImage.SetNativeSize (); do the following:
float aspectRatio = logoSprite.rect.width / logoSprite.rect.height;
var fitter = logoImage.GetComponent<UnityEngine.UI.AspectRatioFitter>();
fitter.aspectRatio = aspectRatio;
I hope this become useful to other members :)
I'd like to have a canvas on my html page, with width = 100%. I'd like to then get the width in pixels of the canvas at runtime. Something like:
Canvas c = Canvas.createIfSupported();
c.setWidth("100%");
c.setHeight("100%");
// let's draw a rectangle to fill the whole canvas:
c.getContext2d().rect(0, 0, ?, ?); // <-- what's its actual width/height?
Thanks
It's (surprisingly)
c.getContext2d().rect(0, 0, 299, 149);
... no matter what the actual pixel size of the canvas is. The reason is, that 300x150 is the default coordinate space size, see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#the-canvas-element
You can change this by using canvas.setCoordinateSpaceWidth() and canvas.setCoordinateSpaceHeight() to anything you want.
Often, people want to draw independently of the actual size of the canvas, so they just set the coordinate space to something like 100x100, and the drawn image gets scaled automatically.
However, you may want to find out about the actual canvas pixel size:
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
final int clientWidth = canvas.getElement().getClientWidth();
final int clientHeight = canvas.getElement().getClientHeight();
setupCoordinateSpace(canvas, clientWidth, clientHeight);
drawMyImage(canvas);
}
});
Note, that this must be done in scheduleDeferred, because the client size will only be known after the browser had a chance to perform the layout.
You can use this information to adjust the aspect ratio to match the canvas (which I would recommend, because otherwise you get distorted images)
void setupCoordinateSpace(Canvas canvas, int clientWidth, int clientHeight) {
final double aspect = (double) clientWidth / (double) clientHeight;
canvas.setCoordinateSpaceHeight(
(int) (myCoordinateSpaceWidth / aspect));
}
Or, alternatively, you can also set the coordinate space to match the pixel size, so you can perform pixel-exact drawing on an HTML5 canvas:
void setupCoordinateSpace(Canvas canvas, int clientWidth, int clientHeight) {
canvas.setCoordinateSpaceWidth(clientWidth);
canvas.setCoordinateSpaceHeight(clientHeight);
}
After the coordinate space has been set up, you can call drawMyImage()
use canvas width and height methods
var width = c.width;
var height = c.height;
I'm looking for best solution - I'm drawing a hexagonal map (Civilization like :) ) for my browser based game in GWT. Currently I'm drawing it on canvas which basically works.
However - I'm also able to slide map left,right,down and up to see another fragment of the map. In such situation I'm forced to redraw the whole map - which doesn't look too good, and will probaly cause preformance issues when the map gets more complex.
Is there a better approach for that? Some library? Or maybe I should make every hex a button like widget. so I could be able to move it instead creating from the scratch... but what about different resolutions then... I'm affraid the map could tear apart sometimes...
You could try doing it will simple DIVs (FlowPanel, HTMLPanel, etc) and style the hexagons using CSS. See this tutorial: http://jtauber.github.com/articles/css-hexagon.html
There are some neat suggestions here as well: html/css hexagon with image inside and hexagonal shaped cells in html
You could draw the entire map (usually just the relatively static background, not the animations!) in a hidden canvas, and then copy the parts you need to your visible canvas:
final Canvas hiddenCanvas = buildCanvas(1000, 1000);
drawHexPattern(hiddenCanvas);
// don't add the hiddenCanvas to your DOM
final Canvas visibleCanvas = buildCanvas(320, 200);
RootPanel.get().add(visibleCanvas); // add the visibleCanvas to the DOM
showArea(hiddenCanvas, visibleCanvas, 0, 0);
...
showArea(hiddenCanvas, visibleCanvas, 20, 10);
...
With a showArea() method like
private void showArea(final Canvas hiddenCanvas, final Canvas visibleCanvas,
final double x, final double y) {
final Context2d hiddenCtx = hiddenCanvas.getContext2d();
final Context2d visibleCtx = visibleCanvas.getContext2d();
final ImageData imageData = hiddenCtx.getImageData(x, y,
visibleCanvas.getCoordinateSpaceWidth(),
visibleCanvas.getCoordinateSpaceHeight());
visibleCtx.putImageData(imageData, 0, 0);
}
I created a pastebin with a working example: http://pastebin.com/tPN2093a
I'm wondering about the behavior of {Shape}.attr("fill","url({image.path})").
when applying a fill image to a shape:
public class AppMapCanvas extends Raphael {
public AppMapCanvas(int width, int height) {
super(width, height);
this.hCenter = width / 2;
this.vCenter = height / 2;
...
Rect rect = this.new Rect(hCenter, vCenter, 144, 40, 4);
rect.attr("fill", "url('../images/app-module-1-bg.png')"); // <--
...
}
}
The background image seem to teal accross the canvas behind the shape, thus gets weird positioning (an illustration snapshot is enclosed - i marked the original image borders in red).
This seem to resolve itself in the presence of an animation along a path (a mere path.M(0,0) is sufficiant).
How can i position the fill-image properly in the first place?
The proper way to do this from what I can understand would be to use an SVG pattern declaration to specify the portion and position of the image you would want to use. Then you would use that pattern to fill the rectangle element. Unfortunately, the Raphael javascript library doesn't have support for patterns... so there's no direct way to use an image to fill a rectangle.