I want for all the Buttons in my game to scale down when user touch down the button and goes back to normal scale as soon as on touch up.What should be be the best possible way.Just like functionality of button in COCOS-2d.
I don't want to use extra small image for button down,if there is other alternative without using extra image.?
Second one is to produce some sound on click,I don't want to this in input listener of every button since sound is same for all buttons.How should i implement this in best possible way.
Thanks in advance.
// i just implement my custom class ,is there is other good way to implement.
public class ImprovedButton extends Button {
boolean isTouchDown=false;// is touch begin
float originalWidth,originalHeight; //actual size
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
if( isPressed()) {
if (!isTouchDown) {
//play sound if any
isTouchDown=true;
originalHeight=getHeight();
originalWidth=getWidth();
setWidth(originalWidth*.95f);
setHeight(originalHeight*.95f);
}
}
else { //pressing is stopper if any
if (isTouchDown) {
isTouchDown=false;
setWidth(originalWidth);
setHeight(originalHeight);
}
}
}
}
one problem with this code is,pivot of scaling bottom left corner.How to set it as center.
I do the same thing on my games.
Make like your custom class for the button.
If you want you can increase the scale in the update method, so the button will scale smooth.
Look here, I wrote for you a example
public class CoolButton {
private Sprite sprite; // the sprite that we are going to use to draw our button
private float scale; // the scale of the button, 1 = full scale, 0.5 half, 2 = twice bigger, etc
public CoolButton(Texture texture, float x, float y, float width, float height) {
sprite = new Sprite(texture);
sprite.setPosition(x, y);
sprite.setSize(width, height);
sprite.setOriginCenter();
scale = 1;
}
public void draw(SpriteBatch batch) {
sprite.setScale(scale); // setting the scale and drawing the button
sprite.draw(batch);
}
// this method should be called when the user touches the screen (don't forget to unproject the coords)
public boolean touchDown(float x, float y) {
if (sprite.getBoundingRectangle().contains(x, y)) { // if the button is touched
scale = 0.7f;
return true;
}
return false;
}
// when you release the touch from the screen make the button back to its normal size
public void touchUp() {
scale = 1f;
}
}
If you have any question please comment here.
Here is a custom class ImprovedButton extends from Button class has additional functionality of Change in SCALE of button and plays SOUND on click .
There is also a class of ImprovedButtonStyle has paramter of scale and sound.
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
public class ImprovedButton extends Button {
boolean isPressedOnce=false;//is press started or touchDown
float originalWidth,originalHeight;
private ImprovedButtonStyle istyle;
public ImprovedButton() {
super();
this.istyle=new ImprovedButtonStyle();
}
public ImprovedButton(Actor child, ImprovedButtonStyle style) {
super(child, style);
this.istyle=style;
}
public ImprovedButton(Actor child, Skin skin, String styleName) {
this(child,skin.get(styleName, ImprovedButtonStyle.class));
}
public ImprovedButton(Actor child, Skin skin) {
this(child,skin.get(ImprovedButtonStyle.class));
}
public ImprovedButton(ImprovedButtonStyle style) {
super(style);
this.istyle=style;
}
public ImprovedButton(Drawable up, Drawable down, Drawable checked) {
super(up, down, checked);
istyle=new ImprovedButtonStyle();
}
public ImprovedButton(Drawable up, Drawable down) {
this(up, down,null);
}
public ImprovedButton(Drawable up) {
this(up,null,null);
}
public ImprovedButton(Skin skin, String styleName) {
super(skin, styleName);
this.istyle=skin.get(ImprovedButtonStyle.class);
}
public ImprovedButton(Skin skin) {
super(skin);
setStyle(skin.get(ButtonStyle.class));
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
if( isPressed()) {
if (!isPressedOnce) {
if (istyle.sound!=null) {
istyle.sound.play();
}
isPressedOnce=true;
originalHeight=getHeight();
originalWidth=getWidth();
setWidth(originalWidth-istyle.changeInWidth);
setHeight(originalHeight-istyle.changeInHeight);
}
}
else {
if (isPressedOnce) {
isPressedOnce=false;
setWidth(originalWidth);
setHeight(originalHeight);
}
}
}
#Override
protected void drawBackground(Batch batch, float parentAlpha, float x,float y) {
int offsetX=0;
int offsetY=0;
if(isPressed()){
offsetX=istyle.changeInWidth/2;
offsetY=istyle.changeInHeight/2;
}
super.drawBackground(batch, parentAlpha, x+offsetX, y+offsetY);
}
public static class ImprovedButtonStyle extends ButtonStyle{
public int changeInWidth=2,changeInHeight=2;
public Sound sound=null;
public ImprovedButtonStyle() {
super();
}
public ImprovedButtonStyle(ButtonStyle style,int changeInWidth,int changeInHeight,Sound sound) {
super(style);
this.changeInHeight=changeInHeight;
this.changeInWidth=changeInWidth;
this.sound=sound;
}
public ImprovedButtonStyle(Drawable up, Drawable down, Drawable checked) {
super(up, down, checked);
}
public ImprovedButtonStyle(ImprovedButtonStyle style) {
super(style);
this.changeInHeight=style.changeInHeight;
this.changeInWidth=style.changeInWidth;
this.sound=style.sound;
}
}
}
Related
I have a gameObject called BounceBack that is supposed to bounce the ball back far away when they collide together.
public class BounceBack : MonoBehaviour
{
public GameObject Player;
public float force;
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag(Player.tag))
{
Player.GetComponent<PlayerController>().ForceBack(force);
}
}
}
The ball Player (ball) script:
public class PlayerController : MonoBehaviour
{
public int acceleration;
public int speedLimit;
public int sideSpeed;
public Text countText;
public Text winText;
public GameObject pickUp;
public GameObject finishLine;
//internal void ForceBack() //Not sure what it does and why it's there.
//{
// throw new NotImplementedException();
//}
private int count;
private Rigidbody rb;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
SetCount();
}
// Update is called once per frame
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal") * sideSpeed * rb.velocity.magnitude / acceleration;
//float moveVertical = Input.GetAxis("Vertical") * acceleration;
if (rb.velocity.magnitude <= speedLimit)
{
rb.AddForce(0.0f, 0.0f, acceleration); // add vertical force
}
rb.AddForce(moveHorizontal, 0.0f, 0.0f); // add horizontal force
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag(pickUp.tag))
{
other.GetComponent<Rotate>().Disapear();
count++;
SetCount();
}
if (other.gameObject.CompareTag(finishLine.tag))
{
acceleration = 0;
sideSpeed = 0;
finishLine.GetComponent<GameEnd>().FadeOut();
if (count >= 2)
{
winText.GetComponent<WinTextFadeIn>().FadeIn("Vous avez remporté la partie!");
}
else
{
winText.GetComponent<WinTextFadeIn>().FadeIn("Vous avez perdu. Réesayer?");
}
}
}
private void SetCount()
{
countText.text = "Count : " + count.ToString();
}
public void ForceBack(float force)
{
Rigidbody rb = GetComponent<Rigidbody>();
rb.AddForce(0.0f, 0.0f, -force, ForceMode.VelocityChange);
Debug.Log("Pass");
}
}
The AddForce function does not do anything. I tried with setActive(false) and it's not working either. The only thing that works is Debug.Log(). I'm not sure if the speedlimit and acceleration are interfering with the function.
EDIT: I'm not sure if the problem is from Unity but I can't access any variable of the class from the forceBack function inside the class.
EDIT2: I also tried to call the AddForce function directly in the Bounce Back script but it's not working either.
Player.GetComponent<Rigidbody>().AddForce(0.0f, 0.0f, -force, ForceMode.VelocityChange);
Player (Ball) Screenshot
Bounce Back Screenshot
So, a couple things:
1.) The physics system should already cause the ball to bounce if you've set up the colliders and rigidbodies properly. You should only need to do something like this if the ball should gain momentum when it bounces, which is unlikely. You should post screenshots of their inspectors if this answer doesn't help.
2.) On your rb.AddForce() call, you're applying a force in world-space, which may be the wrong direction to bounce. If you know the ball is oriented the way it's moving, then you can call AddRelativeForce with the same parameters. If the ball's orientation is not controlled, then you need to calculate the correct world-space direction to use before applying the force.
3.) Finally, just to confirm, the objects with BounceBack attached do have a non-zero value in the 'force' parameter in the inspector, right?
I am building a flappy bird style side scroller game and currently implementing collectible items for the main sprite to collect as it flies. I am not moving the main sprite but moving the background using ParallaxEffect and intend to move the collectibles (called orbs) towards the main sprite (bird). The Orbs are rendered in random positions but the position is not changed even after the update method is called.
Here is my CollectibleOrbs.java
public class CollectibleOrbs {
private static final int ORB_COUNT = 10;
private Array<Orb> orbs;
private Orb orb;
public CollectibleOrbs(){
orbs = new Array<Orb>();
for(int i=0;i<ORB_COUNT; i++) {
orb = new Orb();
orbs.add(orb);
}
}
public void update(float delta){
for(Orb orb: orbs){
orb.update(delta);
}
}
public void render(SpriteBatch sb){
for(Orb orb:orbs){
orb.draw(sb);
}
}
private class Orb{
private ParticleEffect effect;
private Vector2 position;
private Random rand;
public Orb(){
effect = new ParticleEffect();
rand = new Random();
position = new Vector2(rand.nextInt(Gdx.graphics.getWidth()),rand.nextInt(Gdx.graphics.getHeight()));
effect.load(Gdx.files.internal("particle/orbred.p"),
Gdx.files.internal("particle"));
effect.setPosition(position.x,position.y);
}
public void draw(SpriteBatch sb){
effect.draw(sb,Gdx.graphics.getDeltaTime());
}
public void update(float dt){
if(position.x< 10){
position.x = rand.nextInt(Gdx.graphics.getWidth());
position.y = rand.nextInt(Gdx.graphics.getHeight());
}
else
{
position.x-= 100*dt;
}
}
}
}
The orbs are rendered but they are not moving whereas the bird animation and the parallax background does:
I am calling the update method of CollectibleOrb class in the update of my game state and respectively for the render method while passing required parameters. How do to make sure the orbs move on the game screen?
The problem is that position is just unrelated to effect vector. Changing just position won't change effect's position. One way to solve it:
public void update(float dt){
if(position.x< 10){
position.x = rand.nextInt(Gdx.graphics.getWidth());
position.y = rand.nextInt(Gdx.graphics.getHeight());
}
else
{
position.x-= 100*dt;
}
// you should update ParticleEffect position too, just like you did in the constructor
effect.setPosition(position.x, position.y);
}
In my game I implement fling gesture detection. Everything work fine , but I want to modify fling detection
From documentation for fling: https://github.com/libgdx/libgdx/wiki/Gesture-detection
fling: A user dragged the finger across the screen, then lifted it. Useful to implement swipe gestures.
I want to modify this and fling to work without lifting touch, only when user drag some distance not lifting it.
Here is my code:
public class SimpleDirectionGestureDetector extends GestureDetector {
public interface DirectionListener {
void onLeft();
void onRight();
void onUp();
void onDown();
}
public SimpleDirectionGestureDetector(DirectionListener directionListener) {
super(new DirectionGestureListener(directionListener));
}
private static class DirectionGestureListener extends GestureAdapter{
DirectionListener directionListener;
public DirectionGestureListener(DirectionListener directionListener){
this.directionListener = directionListener;
}
#Override
public boolean fling(float velocityX, float velocityY, int button) {
if(Math.abs(velocityX)>Math.abs(velocityY)){
if(velocityX>0){
directionListener.onRight();
}else{
directionListener.onLeft();
}
}else{
if(velocityY>0){
directionListener.onDown();
}else{
directionListener.onUp();
}
}
return super.fling(velocityX, velocityY, button);
}
}
}
public SimpleDirectionGestureDetector gestureDetector = new SimpleDirectionGestureDetector(
new SimpleDirectionGestureDetector.DirectionListener() {
#Override
public void onUp() {
onUpSwipe();
}
#Override
public void onRight() {
onRightSwipe();
}
#Override
public void onLeft() {
onLeftSwipe();
}
#Override
public void onDown() {
onDownSwipe();
}
});
Any help would be appreciated
Thanks
I want to make a text appear in the center of the screen, indicating
the current level. It should appear gradually and after a while disappear gradually. I'm using scene2d with stages, actors.. so i would use Actions.
This is what i have now:
public class TextActor extends Actor {
private BitmapFont font;
private CharSequence charSequence;
public TextActor(CharSequence charSequence) {
font = new BitmapFont(Gdx.files.internal("fonts/white_standard_font.fnt"));
this.charSequence = charSequence;
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
public void draw(Batch batch, float delta) {
super.draw(batch, delta);
font.draw(batch, charSequence, getX(), getY());
}
}
In the class that creates the TextActor..
textActor.addAction(Actions.sequence(Actions.fadeIn(1f), Actions.delay(1f), Actions.fadeOut(1f), new Action() {
#Override
public boolean act(float delta) {
textActor.remove();
transitionInProgress = false;
gameState = GameState.RUNNING;
Gdx.input.setInputProcessor(stage);
return true;
}
}));
gameTable.addActor(textActor);
fadeIn, fadeOut, alpha.. don't work. I tried with "moveBy" and it works, so it seems a problem concerning the appearance of the Actor. There is something that escapes me.
The fade actions modify the alpha value of the Actor's color (getColor().a). You're drawing the font directly without applying the color associated with the actor.
Take a look at how Label.draw is implemented for a better understanding. In the meantime, just try adding this above your font.draw(...) call:
font.setColor(getColor())
Or, if you don't want to modify the entire color, just the alpha, try this:
font.getColor().a = getColor().a;
UPDATE:
Also note that you should apply the parentAlpha (second parameter of draw - labelled as delta in your example) to the final alpha:
font.getColor().a = getColor().a * parentAlpha
This allows your actor to fade if you change the alpha of the stage or any parents.
I've tried to implement a resizeable tooltip but have some problems with this.
When the tooltip is shown, the text updates on change in the model (implemented with property change listener). What I need now is, that the tooltip changes its size as well depending on the text.
Tried revalidate, doLayout and repaint but with no effect. The tooltip doesn't change its size.
Only moving the mouse gives me a correct sizing for the first text which is displayed in the tooltip.
Can anybody help?
Here are some code snippets: first of all my tolltip class:
public class ResizeableToolTip extends JToolTip {
public ResizeableToolTip(final JComponent component) {
super(component);
initComponents();
}
#Override
protected void initGUI() {
super.initGUI();
setLayout(new BorderLayout());
}
/**
* Component initialization goes here...
*/
private void initComponents() {
setTipText(getComponent().getToolTipText());
setPreferredSize(calculateOptimalSize());
}
private abstract Dimension calculateOptimalSize();
#Override
public void setTipText(String tipText) {
super.setTipText(tipText);
setPreferredSize(calculateOptimalSize());
revalidate();
}
}
Then I have a button which is using this implementation:
public class MyButton extends JButton implements PropertyChangeListener {
//...
private ResizeableToolTip tooltip;
//...
private initComponents() {
//...
tooltip = new ResizeableToolTip(this);
//...
}
//...
public void propertyChange(final PropertyChangeEvent pcevt) {
//...
if (MyButtonModel.TOOLTIPTEXT_PROPERTY.equals(pcevt.getPropertyName()) {
tooltip.setTiptext((String) pcevt.getNewValue());
tooltip.repaint();
}
//...
}
//...
}
The result should be a tooltip which is displayed over the button where the text is changing when s.th. changes in the data model. The text changes are working but the size of the box of the tooltip stays on the wrong size.
As far as i can tell there is not way to resize it besides moving the mouse. However the component should have one mouse mouse motion listener so all you have to do is call mouseMoved on that and it will think the mouse has been moved and will resize the tooltip.
//comp will be whatever component your tooltip is on
if(comp.getMouseMotionListeners().length > 0)comp.getMouseMotionListeners()[0].mouseMoved(new MouseEvent(inst, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo().getLocation().y, 0, false));
Just call that after you set the tooltip and it should resize.