I have an object that I am resizing from bottom to top.
private void setStickSize() {
if (MyInputProcessor.isTap) {
stickSprite.setSize(stickSprite.getWidth(),stickSprite.getHeight()+500.0f);
stickSprite.setY(MathUtils.clamp(stickSprite.getY(),0,700));
// MyInputProcessor.isTap = false;
}
Here the sprite is growing out of the screen after calling this in update().I used clamp() to stop this sticksprite within the screen.But no effects on the code.
Why clamp() is not working here?
How can I restrict the sprite resizing effectively within the screen?
I am drawing the sprite like this.
private void drawStick() {
stickSprite.setPosition(stick.getX(),stick.getY());
batch.draw(
stickSprite.getTexture(),stick.getX(),stick.getY(),
stickSprite.getWidth()/2 ,stickSprite.getHeight()/2,
stickSprite.getWidth(),
stickSprite.getHeight()*0.01f,
stickSprite.getScaleX(),stickSprite.getScaleY(), 0,
stickSprite.getRegionX(),stickSprite.getRegionY(),
stickSprite.getRegionWidth(), stickSprite.getRegionHeight(),
false,false);
}
Bound with a condition. Firstly check is your image is out of the screen, if not then increase your image size by a small limit otherwise stop increasing image size.
Like if I have a image(Sprite) and I'm increasing size of that image then we can put a bound before size increment.
if(sprite.getY()+sprite.getHeight()<Gdx.graphics.getHeight()){
float currentHeight=sprite.getHeight();
currentHeight++;
sprite.setSize(sprite.getWidth(),currentHeight);
}
Related
Here's a constructor for a card class I was making. When I create one that is scaled and click on it, only clicks within the 1.0x scaled area are actually registered. i.e. if I pass in 1.5 for the scale, clicks on the borders don't work. Why not? I've scaled the actor itself.
public Card(float x, float y, float scale)
{
this.setPosition(x, y);
faceSprite = new Sprite(MyResources.getInstance().cardTextureRegion);
faceSprite.setPosition(x, y);
faceSprite.setScale(scale);
borderSprite = new Sprite(MyResources.getInstance().cardBorderTextureRegion);
borderSprite.setPosition(x, y);
borderSprite.setScale(scale);
// Set boundaries for ourselves (the actor). Note that we have to match the scale of the sprites.
setSize(borderSprite.getWidth(), borderSprite.getHeight());
setScale(scale);
// Add ClickListener
final Card thisCard = this;
addListener(new ClickListener() {
public void clicked(InputEvent event, float x, float y) {
((MyStage)(thisCard.getStage())).cardClicked(thisCard);
}
});
}
Basic Actor class might be missing some functionalities, including proper scale handling. If all you want is displaying some images (judging by the Sprite objects you use), I'd suggest using the existing classes rather than making custom actors - especially since you might have trouble rendering Sprites with exact Actor parameters if you use a lot of custom actions.
Image allows you to display "sprites" - although somewhat simplified, it should be enough. To store the images, you can use a Table (more flexible) or a Stack (will work with multiple images of the same size).
If you really want to stick with the custom actor approach, try this instead of changing the scale:
setSize(borderSprite.getWidth() * scale, borderSprite.getHeight() * scale);
If you don't change Card scale manually in runtime (only set it up during creation), it should just work.
You Can use image Class to display Images.
Texture texture=new Texture("test.jpg");
Image image=new Image(texture);
//you can use setsize() or setBounds() as per your requirement.
image.setScale(scale);
image.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
((MyStage)(thisCard.getStage())).cardClicked(event.getTarget());
}
});
Is it possible to put viewport inside a custom actor, so that viewport width and height will be actor's width and height, and rendering will start from actor position, no from (0,0).
Stage is a 2D scene graph. It has a hierarchical structure, which means that Actors added to a Group should already be rendered only inside that given Group. Moving the Group will also move all children inside. Via clipBegin() and clipEnd you can also "cut off" everything that's not inside the actor, which is kind of what a Viewport does as well, when setting the glViewport.
So probably you won't need an extra Viewport for whatever you are trying to do. If you still think you need one, you can create an ActorViewport extends Viewport which gets an Actor field. You would have to override the apply(boolean) method and synchronize the worldWidth, worldHeight, screenX, screenY, screenWidth and screenHeight variables to match the Actor. Remember that you will have to update the viewport everytime the actor changes, which is in every frame in the worst case.
Thanks to noone solution was very simple:
public class ActorViewport extends Viewport
{
private Actor m_actor;
public ActorViewport(Actor actor, int worldWidth, int worldHeight, Camera camera)
{
m_actor = actor;
setWorldSize(worldWidth, worldHeight);
setCamera(camera);
}
#Override
public void update(int screenWidth, int screenHeight, boolean centerCamera)
{
setScreenPosition((int)m_actor.getX(), (int)m_actor.getY());
setScreenSize((int)m_actor.getWidth(), (int)m_actor.getHeight());
}
}
Helllo, im new to libgdx, i need some help, if my desktoplauncher resolution is 480x320, sprite takes 80% of the screen, but if 1280x720, sprite is small, i need to make it look the same at all resoltions so how do i do this? may be easy for you, but not for my, im using libgdx 1.3.1
this is my libgdx code:
SpriteBatch batch;
Texture img;
Sprite mysprite;
#Override
public void create ()
{
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
mysprite = new Sprite(img);
stage = new Stage(new StretchViewport(480, 320));
}
StretchViewport myviewport = new StretchViewport(480, 320);
public void resize(int width, int height)
{
// use true here to center the camera
// that's what you probably want in case of a UI
stage.setViewport(myviewport);
stage.getCamera().position.set(640/2, 480/2, 0);
}
private Stage stage;
#Override
public void render ()
{
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
mysprite.draw(batch);
batch.end();
}
You are allready using the right thing: Viewport.
There are different Viewport classes, some of them support working with a virtual screen size, which is what you are looking for.
What is a virtual screen size? Well it is the screen size your code is working with and which is then scaled up to match the real resolution.
Basicly you can work with your own units and they are then automatically scaled up to match pixels.
I guess in your case there are 2 possible Viewport-types:
- StretchViewport supports virtual screen sizes and scales it up to match the real screen size and the real aspect ratio. If the real aspect ration does not match the virtual one the Sprites will be stretched, which could look strange.
- FitViewport is the same as the StretchViewport, but it will keep the aspect ratio. If the real aspect ration does not match the virtual one, black borders will appear.
How to use it:
First you need to create it:
myViewport = new StretchViewport(VIRTUAL_WIDTH, VIRTUAL_HEIGHT);
Then set the Stages Viewport:
stage = new Stage(myViewport);
In the resize method you need to update your Viewport:
myViewport.update(width, height);
Thats all.
The stage now uses the Viewport and its camera to render. You don't need to touch the camera, unless you need to move it arround.
So your errors are:
stage = new Stage(new StretchViewport(480, 320));
Which creates a new StretchViewport you don't store/use.
stage.setViewport(myviewport);
You only need to set it once, when you create the stage
You never call update(width, height) for the Viewport.
I'm trying to add an image to a sprite then add it to the grid. The original size of the image is 276x202. However when it's been added to the grid it increases in size.
http://i.imgur.com/P1Jlq.png
The result is
http://i.imgur.com/0UPBH.png
public class main extends MovieClip
{
public function main()
{
var view:IsoView = new IsoView();
view.setSize((stage.stageWidth), stage.stageHeight);
view.clipContent = true;
addChild(view);
var gridHolder:IsoScene = new IsoScene();
view.addScene(gridHolder);
var scene:IsoScene = new IsoScene();
view.addScene(scene);
graphics.beginFill(0x000000, 1);
graphics.drawRect(0, 0, 800, 600);graphics.endFill();
var grid:IsoGrid = new IsoGrid();
grid.cellSize = 40;
grid.setGridSize(20, 20, 0);
gridHolder.addChild(grid);
gridHolder.render();
//var box:IsoBox = new IsoBox();
//box.setSize(40, 40, 40);
//box.moveTo(80, 80, 0);
//scene.addChild(box);
var player:IsoSprite;
var myLoader:Loader;
myLoader=new Loader();
myLoader.load(new URLRequest('imgs/DesertTankNE.png'));
//myLoader.width = 5; //Makes image disappear no matter what value is set.
//myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, OnComplete); //Doesn't change anything if we say on completion of loading image add it to the sprite.
player = new IsoSprite();
player.sprites = [myLoader];
//player.setSize(1,1,0); //Doesn't seem to affect anything no matter what size specified.
//player.width = 2; //Same as above
scene.addChild(player);
scene.render();
}
}
I've tried setting the width and height of the image when loading it and also tried setting the size of the sprite. The former makes the image not appear no matter what value is set and the latter doesn't seem to affect anything.
There is absolutely nothing wrong with your as3isolib code, and the image is not being resized in any way by code. Compare the tank image to the size of the grid cells (which should be 20 pixels width by 20 pixels height) and you should see that their relative sizes are ok.
The only problem there is that the whole flash stage is being resized. Are you testing your flash movie on the browser perhaps? Make sure you aren't setting the flash movie's width and height as 100% of its container in the HTML. If the flash movie is in a div and flash is told to be a width and height of 100%, it will stretch out to whatever size the div is.
Seeing your code I think you want your stage size to be 800x600; set your flash movie to those dimensions using the metatag SWF, for example:
[SWF(width="800", height="600", frameRate="30", backgroundColor="#FFFFFF")]
If you are using Flash Builder, you might need to clean your project a couple of times (Project -> Clean) to clear the previous compiler settings. Test your SWF movie outside of the broswer (double click the SWF file to open it on your local flash player) and make sure it has the proper dimensions. You should see the tank and the grid cells the right size now.
If you want to test it in the browser, don't use the HTML wrapper generated by Flash Builder (or Flash Pro). Make your own html using swfobject and set the correct width and height, for example:
<script type="text/javascript">
swfobject.embedSWF("myIsoTank.swf", "flash_container_div", "800", "600", "10", "expressInstall.swf");
</script>
This should get rid of your problem.
Just a little background on what I am trying to do. I have a custom skin where I have a stylable text field to display the date. When clicking on the stylable text field, which is binded to the date, a date spinner comes up. Behind the datespinner I draw a sprite which needs to cover the whole screen so I can detect a click and make the datespinner go away.
Now the problem-
Without overriding the get width or get height I haven't been able to fill the whole screen. However when I do this the datespinner breaks because its getting the height from the override. Just wondering if anyone knew a way to override just one component and set all others to their default values. I know this might seem like a noob question and maybe I am missing something obvious, I am mostly new to as3.
Here is some code-
override protected function createChildren():void {
super.createChildren();
if(!img) {
img = new dateButtonBG();
addChild(img);
}
if (!maskSprite) {
maskSprite = new Sprite();
maskSprite.graphics.beginFill(0xFFFFCC, .5);
maskSprite.graphics.drawRect(-((stage.height)/2),-((stage.width)/2), stage.width, stage.height);
maskSprite.graphics.endFill();
}
if(!dateButton) {
dateButton = new StyleableTextField();
todayDate = new Date();
BindingUtils.bindProperty(dateButton, "text", date, "selectedDate");
dateButton.addEventListener(MouseEvent.CLICK, onDateButtonClick);
addChild(dateButton);
}
invalidateDisplayList();
}
protected function removeSpinner( event:Event):void{
maskSprite.removeEventListener(MouseEvent.CLICK, removeSpinner);
removeChild(date);
removeChild(maskSprite);
}
protected function onDateButtonClick (event:Event):void {
addChild(maskSprite);
addChild(date);
maskSprite.addEventListener(MouseEvent.CLICK, removeSpinner);
}
override public function get width () : Number {
return _width;
}
override public function get height () : Number {
return _height;
}
The code is not complete but is just for getting my point across. Thanks for reading and all your help.
EDIT-
I figured out how to do it.Adding some information in case some one has the same problem-
Flex limits the size of your sprite( or any UI component) to the size of the container. If you try to go over the size of the container it just returns the size of the container. In my code-
override public function get width () : Number {
return _width;
}
override public function get height () : Number {
return _height;
}
This is commonly touted as a fix to go over the size of the container. This approach is flawed however because it overrides everything that asks for width and height. In this case it tries to make everything the size of _height and _width. For any skin that has more than 1 component this is a huge problem, either you can try to set sizes for items indivigually, which for me didn't work or find an alternate approach.
Here is what works-
public override function validateDisplayList():void {
super.validateDisplayList();
yourComponent.width = someConstantW;
yourComponent.height = someConstantH;
}
This is not going to be enough however. You might need to move your component outside of the container for this try-
override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number):void {
super.layoutContents(unscaledWidth, unscaledHeight);
setElementPosition(yourComponent, x, y);
}
Hopefully I saved someone a few hours of work :)
It's not quite clear from the code you have posted, but perhaps you should be overriding the updateDisplayList() method instead of the width and height.
updateDisplayList() is the Flex life cycle method that components implement to size and position their child objects.
updateDisplayList() is called by the Flex framework, and it passes in two values: unscaledWidth and unscaledHeight. Your implmentation of updateDisplayList() should honor those values and size/position the child objects accordingly. You should use other life cycle methods (shown below) to do the actual sizing/positioning.
Here's an example implementation to get you started. It may be off a little, as I don't fully understand the code snippet you provided.
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
// size/position the background (or whatever it is that should occupy the whole screen)
background.setLayoutBoundsPosition(0,0); // unnecessary because 0,0 is default
background.setLayoutBoundsSize(unscaledWidth, unscaledHeight);
// size/position the text in the center
var textWidth:Number = text.getPreferredBoundsWidth;
var textheight:Number = text.getPreferredBoundsHeight
text.setLayoutBoundsPosition( (unscaledWidth - textWidth)/2, (unscaledHeight - textHeight)/2 );
text.setLayoutBoundsSize(textWidth, textHeight); // probably not necessary
}