Android Studio 開發實踐——簡易版音遊APP(四)

滑塊滑動&滑塊點擊&good、best、miss效果實現

 

 

        實現思路大致是,設置滑塊(繼承自button)對象,兩個軌道每個軌道都對應一個ArrayList<EachButton>滑塊列表,每個滑塊都定義了它的軌道位置、滑動動畫、起始時間、滑動時間、滑動路徑的屬性。

       遊戲頁面得到來自模式選擇頁面的會話,傳遞過來了音頻信息、模式信息,然後調用節奏點獲取的HandleData類來獲取音頻的節奏時間點N個,初始化N個滑塊,將‘節奏時間點-滑動時間’作爲滑塊的滑動動畫延遲時間(這樣滑到按鈕處時就剛好到那個樂點了),將模式信息中的速度、滑塊多少等來量化滑塊移動時間、節奏點個數的信息,然後開始全部滑塊的start方法來開啓動畫。

        點擊下方的FREE按鈕會觸發方法,得到該按鈕所在軌道的最近一個滑塊的位置,與按鈕的位置作比較給出good、best級別,將該滑塊移出軌道隊列;如果滑塊動畫結束仍沒被點擊(還在隊列),則判斷爲miss,並移出隊列。

 

滑塊移動動畫核心代碼爲:

   Path path=new Path();
   path.moveTo(fromX,fromY);//設置path開始座標
   path.lineTo(toX,toY);//設置path結束座標
   animator=ObjectAnimator.ofFloat(this,
           Property.of(EachButton.class,Float.class,"translationX"),
           Property.of(EachButton.class,Float.class,"translationY"),
           path);//設置animator是沿着path路徑這種方式移動的

   animator.setDuration(time);//設置動畫時長,即整個移動過程的時間
   animator.setStartDelay(startTime);//設置動畫延遲時間,到節奏點了再讓滑塊動
   LinearInterpolator lin = new LinearInterpolator();//勻速運動
   animator.setInterpolator(lin);

   animator.addListener(new Animator.AnimatorListener() {
       @Override
       public void onAnimationStart(Animator animation) {
           mlayout.addView(eachButton);
       }

       @Override
       public void onAnimationEnd(Animator animation) {
           mlayout.removeView(eachButton);
       }
   });

good、best、miss提示的彈出、淡化、消失的僞跳躍漸變效果的核心代碼爲:

   View view = LayoutInflater.from(mcontext).inflate(R.layout.toast, null);//得到視圖裏的toast,更新toast的文本爲miss
   TextView textView = view.findViewById(R.id.textView);
   textView.setText("miss");
   Toast toast = GameActivity.toast;//(設置一個toast變量,有初始樣式,每次點擊後更新它的TextView,並show()出來即可)
   toast.setView(view);//更新toast的樣式
   toast.setDuration(Toast.LENGTH_SHORT);

   ObjectAnimator.ofArgb(textView, "textColor",
           Color.parseColor("#ff333333"),
           Color.parseColor("#00333333"))
           .setDuration(1000)
           .start();//設置toast的動畫顯示時間及顏色變化(灰色到灰色透明這種僞漸變效果)
   toast.show();//展示這個toast

 底部按鈕點擊時變色的核心代碼爲:

   ObjectAnimator.ofArgb(bottoms[i], "backgroundColor",
           Color.parseColor("#F3E77C"),
           Color.parseColor("#F8E097"))
           .setDuration(500)
           .start();

 

toast.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/toast"
    >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textView"
        android:text=""
        android:textStyle="bold"
        android:textSize="40sp"
        android:shadowRadius="7.0"
        android:shadowDx="-7"
        android:shadowDy="7"
        android:shadowColor="@color/colorSilver"
        android:layout_marginBottom="125dp"
        android:layout_gravity="center_horizontal"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        ></TextView><!--這裏是constraintlayout,與底部左邊的距離依靠具體手機分辨率決定-->

</androidx.constraintlayout.widget.ConstraintLayout>

 

EachButton類

package com.example.free.Classes;


import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Path;
import android.util.Property;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.widget.AppCompatButton;
import androidx.constraintlayout.widget.ConstraintLayout;

import com.example.free.GameActivity;
import com.example.free.R;
import com.example.free.ResultActivity;

import java.util.Timer;
import java.util.TimerTask;


public class EachButton extends AppCompatButton {

    //這裏的座標位置都是用的像素px,因爲實時獲得滑塊的運動位置得到返回值是像素
    int fromX=0;//滑塊移動的起始點x座標
    int fromY=0;//起始點y座標
    int toX=0;//滑塊移動的終止點x座標
    int toY=0;//終止點y座標
    int startTime=0;//開始移動的時間點
    int time=0;//滑動過程的時間長度

    int width=240;//px 滑塊寬
    int height=120;//滑塊長

    ConstraintLayout mlayout;//滑塊所在的視圖
    Context mcontext;//滑塊所在的上下文活動

    public ObjectAnimator animator;//動畫實例

    public boolean state=true;//按鈕的狀態,是否還存在於隊列中

    int path=0;//所在軌道

   public EachButton(Context context,int _width,int _height,int fx,int fy,int tox,int toy,int st,int t,int p){
        super(context);

        this.fromX=fx;
        this.fromY=fy;
        this.toX=tox;
        this.toY=toy;
        this.startTime=st;
        this.time=t;
        this.path=p;
        width=_width;
        height=_height;

        mcontext=context;

        this.setBackgroundColor(0xaaF8E097);
        this.setWidth(width);
        this.setHeight(height);
        this.layout(1000,0,1000+width,height);//layout裏的參數是滑塊初始位置的四個頂點的座標(左上x,左上y,右下x,右下y)

    }

    //通過設置滑塊動畫的延遲時間,比如20s時是一個節奏點,我們從一開始就初始化了滑塊的動畫,設置延遲時間爲20s
    public void start(ConstraintLayout layout){

        mlayout=layout;
        Path path=new Path();
        path.moveTo(fromX,fromY);//設置path開始座標
        path.lineTo(toX,toY);//設置path結束座標
        animator=ObjectAnimator.ofFloat(this,
                Property.of(EachButton.class,Float.class,"translationX"),
                Property.of(EachButton.class,Float.class,"translationY"),
                path);//設置animator是沿着path路徑這種方式移動的

        animator.setDuration(time);//設置動畫時長,即整個移動過程的時間
        animator.setStartDelay(startTime);//設置動畫延遲時間,到節奏點了再讓滑塊動

        LinearInterpolator lin = new LinearInterpolator();//勻速運動
        animator.setInterpolator(lin);

        final EachButton eachButton=this;//設置滑塊動畫監聽動作,等到動畫結束後"銷燬"該滑塊,方便進行下一次點擊計算,否則點擊動作識別的一直是第一個滑塊
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                mlayout.addView(eachButton);//
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                mlayout.removeView(eachButton);//動畫結束移除該滑塊

                //滑塊的消除(移出buttons隊列)由兩種行爲觸發,一種是點擊,一種是沒點到過去了的miss狀態,以下是第二種
                if(eachButton.state) {//eachButton還在隊列裏,但動畫結束了,這意味着沒點擊成功
                    View view = LayoutInflater.from(mcontext).inflate(R.layout.toast, null);//得到視圖裏的toast,更新toast的文本爲miss
                    TextView textView = view.findViewById(R.id.textView);
                    textView.setText("miss");
                    Toast toast = GameActivity.toast;

                    toast.setView(view);//更新toast的樣式
                    toast.setDuration(Toast.LENGTH_SHORT);

                    ObjectAnimator.ofArgb(textView, "textColor",
                            Color.parseColor("#ff333333"),
                            Color.parseColor("#00333333"))
                            .setDuration(1000)
                            .start();//設置toast的動畫顯示時間及顏色變化(灰色到灰色透明這種僞漸變效果)
                    toast.show();//展示這個toast

                    GameActivity.buttons.get(eachButton.path).remove(0);//將button移出隊列
                    GameActivity.missTimes+=1;//miss次數加一

                    
//如果最後一個滑塊是由miss結尾的,則在這裏結束隊列並且跳轉至成績結算頁面
if((GameActivity.buttons.get(0).size()+GameActivity.buttons.get(1).size()==0)&&GameActivity.activityState) {
                        final Intent iintent = new Intent(mcontext, ResultActivity.class);
                        iintent.putExtra("wholeScore",GameActivity.wholeScore);
                        iintent.putExtra("resultScore",GameActivity.resultScore);
                        iintent.putExtra("bestTimes",GameActivity.bestTimes);
                        iintent.putExtra("goodTimes",GameActivity.goodTimes);
                        iintent.putExtra("missTimes",GameActivity.missTimes);
                        TimerTask task = new TimerTask(){
                            public void run(){
                                mcontext.startActivity(iintent);
                            }
                        };
                        Timer timer = new Timer();
                        timer.schedule(task, 2000);
                    }
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }
            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

        animator.start();//開始動畫

    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章