com.esotericsoftware.spine.superspineboy.PlayerView.java Source code

Java tutorial

Introduction

Here is the source code for com.esotericsoftware.spine.superspineboy.PlayerView.java

Source

/******************************************************************************
 * Spine Runtimes Software License
 * Version 2.1
 * 
 * Copyright (c) 2013, Esoteric Software
 * All rights reserved.
 * 
 * You are granted a perpetual, non-exclusive, non-sublicensable and
 * non-transferable license to install, execute and perform the Spine Runtimes
 * Software (the "Software") solely for internal use. Without the written
 * permission of Esoteric Software (typically granted by licensing Spine), you
 * may not (a) modify, translate, adapt or otherwise create derivative works,
 * improvements of the Software or develop new applications using the Software
 * or (b) remove, delete, alter or obscure any trademarks or any copyright,
 * trademark, patent or other intellectual property or proprietary rights notices
 * on or in the Software, including any copy thereof. Redistributions in binary
 * or source form must include this license and terms.
 * 
 * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *****************************************************************************/

package com.esotericsoftware.spine.superspineboy;

import static com.esotericsoftware.spine.superspineboy.Model.*;
import static com.esotericsoftware.spine.superspineboy.Player.*;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.esotericsoftware.spine.Animation;
import com.esotericsoftware.spine.AnimationState;
import com.esotericsoftware.spine.AnimationState.AnimationStateAdapter;
import com.esotericsoftware.spine.Bone;
import com.esotericsoftware.spine.Event;
import com.esotericsoftware.spine.EventData;
import com.esotericsoftware.spine.Skeleton;
import com.esotericsoftware.spine.superspineboy.Assets.SoundEffect;
import com.esotericsoftware.spine.superspineboy.Model.State;

/** The view class for the player. */
class PlayerView extends CharacterView {
    Player player;
    Bone rearUpperArmBone, rearBracerBone, gunBone, headBone, torsoBone, frontUpperArmBone;
    Animation shootAnimation, hitAnimation;
    boolean canShoot;
    float burstShots, burstTimer;
    Vector2 temp1 = new Vector2(), temp2 = new Vector2();

    PlayerView(final View view) {
        super(view);
        player = view.player;

        skeleton = new Skeleton(view.assets.playerSkeletonData);
        rearUpperArmBone = skeleton.findBone("rear_upper_arm");
        rearBracerBone = skeleton.findBone("rear_bracer");
        gunBone = skeleton.findBone("gun");
        headBone = skeleton.findBone("head");
        torsoBone = skeleton.findBone("torso");
        frontUpperArmBone = skeleton.findBone("front_upper_arm");

        shootAnimation = view.assets.playerSkeletonData.findAnimation("shoot");
        hitAnimation = view.assets.playerSkeletonData.findAnimation("hit");

        animationState = new AnimationState(view.assets.playerAnimationData);

        // Play footstep sounds.
        final EventData footstepEvent = view.assets.playerSkeletonData.findEvent("footstep");
        animationState.addListener(new AnimationStateAdapter() {
            public void event(int trackIndex, Event event) {
                if (event.getData() == footstepEvent) {
                    if (event.getInt() == 1)
                        SoundEffect.footstep1.play();
                    else
                        SoundEffect.footstep2.play();
                }
            }
        });
    }

    void update(float delta) {
        // When not shooting, reset the number of burst shots.
        if (!view.touched && burstTimer > 0) {
            burstTimer -= delta;
            if (burstTimer < 0)
                burstShots = 0;
        }

        // If jump was pressed in the air, jump as soon as grounded.
        if (view.jumpPressed && player.isGrounded())
            jump();

        skeleton.setX(player.position.x + width / 2);
        skeleton.setY(player.position.y);

        if (!setAnimation(view.assets.playerStates.get(player.state), player.stateChanged))
            animationState.update(delta);
        animationState.apply(skeleton);

        Vector2 mouse = temp1.set(Gdx.input.getX(), Gdx.input.getY());
        view.viewport.unproject(mouse);

        // Determine if the player can shoot at the mouse position.
        canShoot = false;
        if (rearUpperArmBone == null || rearBracerBone == null || gunBone == null)
            canShoot = true;
        else if (player.hp > 0 && !view.ui.hasSplash
                && (Math.abs(skeleton.getY() - mouse.y) > 2.7f || Math.abs(skeleton.getX() - mouse.x) > 0.75f)) {
            // Store bone rotations from the animation that was applied.
            float rearUpperArmRotation = rearUpperArmBone.getRotation();
            float rearBracerRotation = rearBracerBone.getRotation();
            float gunRotation = gunBone.getRotation();
            // Straighten the arm and don't flipX, so the arm can more easily point at the mouse.
            rearUpperArmBone.setRotation(0);
            float shootRotation = 11;
            if (animationState.getCurrent(1) == null) {
                rearBracerBone.setRotation(0);
                gunBone.setRotation(0);
            } else
                shootRotation += 25; // Use different rotation when shoot animation was applied.
            skeleton.setFlipX(false);
            skeleton.updateWorldTransform();

            // Compute the arm's angle to the mouse, flipping it based on the direction the player faces.
            Vector2 bonePosition = temp2.set(rearUpperArmBone.getWorldX() + skeleton.getX(),
                    rearUpperArmBone.getWorldY() + skeleton.getY());
            float angle = bonePosition.sub(mouse).angle();
            float behind = (angle < 90 || angle > 270) ? -1 : 1;
            if (behind == -1)
                angle = -angle;
            if (player.state == State.idle
                    || (view.touched && (player.state == State.jump || player.state == State.fall)))
                player.dir = behind;
            if (behind != player.dir)
                angle = -angle;
            if (player.state != State.idle && behind != player.dir) {
                // Don't allow the player to shoot behind themselves unless idle. Use the rotations stored earlier from the animation.
                rearBracerBone.setRotation(rearBracerRotation);
                rearUpperArmBone.setRotation(rearUpperArmRotation);
                gunBone.setRotation(gunRotation);
            } else {
                if (behind == 1)
                    angle += 180;
                // Adjust the angle upward based on the number of shots in the current burst.
                angle += kickbackAngle * Math.min(1, burstShots / kickbackShots) * (burstTimer / burstDuration);
                float gunArmAngle = angle - shootRotation;
                // Compute the head, torso and front arm angles so the player looks up or down.
                float headAngle;
                if (player.dir == -1) {
                    angle += 360;
                    if (angle < 180)
                        headAngle = 25 * Interpolation.pow2In.apply(Math.min(1, angle / 50f));
                    else
                        headAngle = -15 * Interpolation.pow2In.apply(1 - Math.max(0, angle - 310) / 50f);
                } else {
                    if (angle < 360)
                        headAngle = -15 * Interpolation.pow2In.apply(1 - Math.max(0, (angle - 310) / 50f));
                    else
                        headAngle = 25 * Interpolation.pow2In.apply(1 - Math.max(0, (410 - angle) / 50f));
                }
                float torsoAngle = headAngle * 0.75f;
                if (headBone != null)
                    headBone.setRotation(headBone.getRotation() + headAngle);
                if (torsoBone != null)
                    torsoBone.setRotation(torsoBone.getRotation() + torsoAngle);
                if (frontUpperArmBone != null)
                    frontUpperArmBone.setRotation(frontUpperArmBone.getRotation() - headAngle * 1.4f);
                rearUpperArmBone.setRotation(gunArmAngle - torsoAngle - rearUpperArmBone.getWorldRotation());
                canShoot = true;
            }
        }

        skeleton.setFlipX(player.dir == -1);
        skeleton.updateWorldTransform();
    }

    void jump() {
        view.jumpPressed = false;
        player.jump();
        setAnimation(view.assets.playerStates.get(State.jump), true);
    }

    void shoot() {
        if (!canShoot || player.shootTimer >= 0)
            return;
        player.shootTimer = shootDelay;
        burstTimer = burstDuration;

        // Compute the position and velocity to spawn a new bullet.
        float x = skeleton.getX(), y = skeleton.getY();
        if (rearUpperArmBone != null && rearBracerBone != null && gunBone != null) {
            x += rearUpperArmBone.getWorldX();
            y += rearUpperArmBone.getWorldY();
        } else {
            x += width / 2;
            y += height / 2;
        }
        float mouseX = Gdx.input.getX(), mouseY = Gdx.input.getY();

        float angle = view.viewport.unproject(temp1.set(mouseX, mouseY)).sub(x, y).angle();
        angle += kickbackAngle * Math.min(1, burstShots / kickbackShots) * player.dir;
        float variance = kickbackVariance * Math.min(1, burstShots / kickbackVarianceShots);
        angle += MathUtils.random(-variance, variance);

        float cos = MathUtils.cosDeg(angle), sin = MathUtils.sinDeg(angle);
        float vx = cos * bulletSpeed + player.velocity.x * bulletInheritVelocity;
        float vy = sin * bulletSpeed + player.velocity.y * bulletInheritVelocity;
        if (rearUpperArmBone != null && rearBracerBone != null && gunBone != null) {
            x = skeleton.getX() + gunBone.getWorldX();
            y = skeleton.getY() + gunBone.getWorldY() + shootOffsetY * scale;
            x += cos * shootOffsetX * scale;
            y += sin * shootOffsetX * scale;
        }
        model.addBullet(x, y, vx, vy, temp1.set(vx, vy).angle());
        if (shootAnimation != null)
            animationState.setAnimation(1, shootAnimation, false);

        view.camera.position.sub(view.shakeX, view.shakeY, 0);
        view.shakeX += View.cameraShake * (MathUtils.randomBoolean() ? 1 : -1);
        view.shakeY += View.cameraShake * (MathUtils.randomBoolean() ? 1 : -1);
        view.camera.position.add(view.shakeX, view.shakeY, 0);

        player.velocity.x -= kickback * player.dir;
        SoundEffect.shoot.play();

        burstShots = Math.min(kickbackShots, burstShots + 1);
    }
}