vault.clockwork.actors.HandActor.java Source code

Java tutorial

Introduction

Here is the source code for vault.clockwork.actors.HandActor.java

Source

/*
 * The MIT License
 *
 * Copyright 2015 Konrad Nowakowski https://github.com/konrad92.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package vault.clockwork.actors;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import vault.clockwork.Game;
import vault.clockwork.controllers.CameraController;
import vault.clockwork.editor.PropSerialized;
import vault.clockwork.scene.Actor;
import vault.clockwork.scene.Entity;
import vault.clockwork.system.SceneController;

/**
 * A floating hand controlled by the player.
 * @author Konrad Nowakowski https://github.com/konrad92
 */
public class HandActor extends Actor {
    /**
     * Stany rozgrywki `roncki`.
     */
    public interface HandState {
        /**
         * Gdy gracz wejdzie w stan.
         */
        public default void enter() {
            // dummy method
        }

        /**
         * Gdy gracz wyjdzie ze stanu.
         */
        public default void leave() {
            // dummy method
        }

        /**
         * Aktualizuj stan.
         * @param delta 
         */
        public void update(float delta);

        /**
         * Rysuj stan.
         * @param batch 
         */
        public void draw(SpriteBatch batch);
    };

    /**
     * Hand texture filename.
     */
    static public final String HAND_TEXTURE = "assets/hand.png",
            STAMINABAR_BG_TEXTURE = "assets/stamina-bar-bg.png",
            STAMINABAR_MD_TEXTURE = "assets/stamina-bar-md.png",
            STAMINABAR_FG_TEXTURE = "assets/stamina-bar-fg.png";

    /**
     * Preload the actor resources.
     */
    static public void preload() {
        Game.assets.load(HAND_TEXTURE, Texture.class);
        Game.assets.load(STAMINABAR_BG_TEXTURE, Texture.class);
        Game.assets.load(STAMINABAR_FG_TEXTURE, Texture.class);
        Game.assets.load(STAMINABAR_MD_TEXTURE, Texture.class);
    }

    /**
     * Hand position on the scene.
     */
    public final Vector2 position = new Vector2();

    /**
     * Hand sprite.
     */
    private final Sprite sprHand;
    private final Sprite sprStaminaBG;
    private final Sprite sprStaminaFG;
    private final Sprite sprStaminaMD;

    /**
     * Paper ball actor assigned for cooldown process.
     */
    private PaperBallActor paperBall;

    /**
     * Stamina level. Determines strength of the shoot.
     */
    private float staminaLevel = 0.f;

    /**
     * Stan gotowosci gracza do wystrzalu.
     */
    public final HandState STATE_IDLE = new HandState() {
        @Override
        public void update(float delta) {
        }

        @Override
        public void draw(SpriteBatch batch) {
            // update sprite position
            sprHand.setPosition(position.x - sprHand.getOriginX(), position.y - sprHand.getOriginY());

            // draw-up the hand sprite
            batch.begin();
            sprHand.draw(batch);
            batch.end();
        }
    };

    /**
     * Stan gotowosci gracza do wystrzalu.
     */
    public final HandState STATE_READY = new HandState() {
        @Override
        public void enter() {
            paperBall = null;
        }

        @Override
        public void update(float delta) {
            Vector2 rotateBy = getPointerVector().nor();

            // flip the hand
            if (rotateBy.x < 0) {
                sprHand.setFlip(false, true);
            } else {
                sprHand.setFlip(false, false);
            }

            // shoot the paper ball
            if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
                setState(STATE_LOADING);
            }

            // follow the cursor
            //sprHand.setRotation(rotateBy.angle());
            lerpRotateTo(rotateBy, 5.f * delta, 20.f);
        }

        @Override
        public void draw(SpriteBatch batch) {
            STATE_IDLE.draw(batch);
        }
    };

    /**
     * Stan ladowania sily.
     */
    public final HandState STATE_LOADING = new HandState() {
        @Override
        public void enter() {
            staminaLevel = 0.f;
        }

        @Override
        public void update(float delta) {
            staminaLevel = Math.min(staminaLevel + 1.4f * delta, 1.f);

            if (!Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
                shootPaperBall();
                setState(STATE_READY);
            }
        }

        @Override
        public void draw(SpriteBatch batch) {
            STATE_IDLE.draw(batch);

            // draw stamina bar
            float scale = Game.mainCamera.zoom;

            sprStaminaBG.setScale(Game.mainCamera.zoom);
            sprStaminaBG.setCenter(position.x, position.y + 200.f * scale);

            sprStaminaFG.setScale(Game.mainCamera.zoom);
            sprStaminaFG.setCenter(position.x, position.y + 200.f * scale);

            // stamina level
            float level = (float) sprStaminaMD.getTexture().getWidth() * Math.min(staminaLevel, 1.f);
            sprStaminaMD.setScale(Game.mainCamera.zoom);
            sprStaminaMD.setPosition(position.x - sprStaminaBG.getWidth() * .5f, sprStaminaBG.getY());
            sprStaminaMD.setSize(level, sprStaminaMD.getHeight());
            sprStaminaMD.setRegionWidth((int) (level));

            // draw-up the stamina sprites
            batch.begin();
            sprStaminaBG.draw(batch);
            sprStaminaMD.draw(batch);
            sprStaminaFG.draw(batch);
            batch.end();
        }
    };

    /**
     * Aktualny stan rozgrywki.
     */
    private HandState currentState = null;

    public HandActor(PropSerialized prop) {
        this(prop.id);
        this.setPosition(prop.position);

        // centrowanie kamery
        for (SceneController ctrl : Game.scene.controllers) {
            if (ctrl instanceof CameraController) {
                ((CameraController) ctrl).camera.translate(position);
            }
        }
    }

    /**
     * Ctor.
     * @param id Unique actor ID 
     */
    public HandActor(int id) {
        super(id, TYPE_PLAYER);

        // create hand sprite
        sprHand = new Sprite(Game.assets.get(HAND_TEXTURE, Texture.class));
        sprHand.setOrigin(270.f, 94.f);
        sprHand.setScale(.8f);
        setPosition(Vector2.Y.cpy().scl(200.f));

        // create stamina bar sprites
        sprStaminaBG = new Sprite(Game.assets.get(STAMINABAR_BG_TEXTURE, Texture.class));
        sprStaminaFG = new Sprite(Game.assets.get(STAMINABAR_FG_TEXTURE, Texture.class));
        sprStaminaMD = new Sprite(Game.assets.get(STAMINABAR_MD_TEXTURE, Texture.class));

        // zmien stan rozgrywki
        setState(STATE_READY);
    }

    /**
     * Controll the hand by mouse pointer.
     * @see Actor#update(float) 
     * @param delta 
     */
    @Override
    public void update(float delta) {
        // aktualizacja aktualnie rozgrywanego stanu
        if (currentState != null) {
            currentState.update(delta);
        }
    }

    /**
     * @see Actor#draw(com.badlogic.gdx.graphics.g2d.SpriteBatch) 
     * @param batch 
     */
    @Override
    public void draw(SpriteBatch batch) {
        // rysowanie aktualnie rozgrywanego stanu
        if (currentState != null) {
            currentState.draw(batch);
        }
    }

    /**
     * @see Entity#debug(com.badlogic.gdx.graphics.glutils.ShapeRenderer) 
     * @param gizmo 
     */
    @Override
    public void debug(ShapeRenderer gizmo) {
        gizmo.begin(ShapeRenderer.ShapeType.Line);
        gizmo.circle(position.x, position.y, 16.f);
        gizmo.end();
    }

    /**
     * Zmiany zwroconej referencji dadza efekt.
     * @see Actor#getPosition() 
     * @return 
     */
    @Override
    public Vector2 getPosition() {
        return position;
    }

    /**
     * @see Actor#setPosition(com.badlogic.gdx.math.Vector2) 
     * @param newPosition 
     */
    @Override
    public void setPosition(Vector2 newPosition) {
        position.set(newPosition);
    }

    /**
     * @see Actor#getRotation() 
     * @return 
     */
    @Override
    public float getRotation() {
        return sprHand.getRotation();
    }

    /**
     * @see Actor#setRotation(float) 
     * @param newAngle degrees
     */
    @Override
    public void setRotation(float newAngle) {
        sprHand.setRotation(newAngle);
    }

    /**
     * Zmien aktualnie rozgrywany stan.
     * @param newState 
     */
    public void setState(HandState newState) {
        // leave current state
        if (currentState != null) {
            currentState.leave();
        }

        // enter to the new state
        currentState = newState;
        if (currentState != null) {
            currentState.enter();
        }
    }

    /**
     * Wystrzeliwuje kulke, gdy ta nie jest jeszcze wystrzelona.
     */
    public void shootPaperBall() {
        if (paperBall != null) {
            return;
        }

        // kierunek i sila wystrzalu
        Vector2 force = Vector2.X.cpy().setAngle(getRotation()).scl(staminaLevel * 500.f);

        // stworz kulke
        paperBall = new PaperBallActor(0);
        paperBall.setPosition(position);
        paperBall.applyForce(force);
        Game.scene.ACTION_1.add(paperBall);
    }

    /**
     * Get the pointer vector, from the hand to the cursor.
     * @return 
     */
    public Vector2 getPointerVector() {
        Vector3 rotateBy = Game.mainCamera
                .unproject(new Vector3(Gdx.input.getX() - position.x / Game.mainCamera.zoom,
                        Gdx.input.getY() + position.y / Game.mainCamera.zoom, 0.f));

        return new Vector2(rotateBy.x, rotateBy.y);
    }

    /**
     * Calculate angle difference of hand by a given vector.
     * @param by
     * @return 
     */
    private float angleDifference(Vector2 by) {
        return by.angle(Vector2.X.cpy().setAngle(sprHand.getRotation()));
    }

    /**
     * Lerp interpolation of the angle.
     * @param target
     * @param factor 
     */
    private void lerpRotateTo(Vector2 target, float factor) {
        sprHand.rotate(angleDifference(target) * -factor);
    }

    /**
     * Lerp interpolation of the angle.
     * Clamp the interpolation.
     * @param target
     * @param factor 
     */
    private void lerpRotateTo(Vector2 target, float factor, float clamp) {
        sprHand.rotate(MathUtils.clamp(angleDifference(target) * -factor, -clamp, clamp));
    }
}