android遊戲開發框架libgdx的使用(四)–舞臺和演員 – Android移動開發技術文章_手機開發 Android移動開發教學課程

我們先看幾個遊戲截圖再來理解何為舞臺。

12942M3Q423F-45025

請仔細觀察圖片中的元素,有些東西是不能動,有些可以動,有些有特效,有些沒有。有些是按鈕,有些是圖片,但是其實它們都可以統一稱為演員(Actor)。

而整個遊戲界面就是我們的舞臺。

12942M3Q423F-45025 - 副本

再看一個射擊類遊戲

f2316c3c29ce2660f93dce72a0944453

而其中的演員是

f2316c3c29ce2660f93dce72a0944453

演員是遊戲設計中常用的一個對象,它接受舞臺的統一管理,擁有一些公共的事件,比如觸摸,點擊,但是同時還有自身的響應和屬性。

而舞臺就是容納演員的場所。它統一管理所有演員,接受輸入,同時提供一個方便的框架操作演員的時間變化。

我們來看一下Stage類:


protected final Group root; 

protected final SpriteBatch batch;  

protected Camera camera;

它擁有一個Group,一個SpriteBatch,還有一個相機。

SpriteBatch我們在前幾篇說過,這裡就不再重復瞭。

Group是一個類,用於容納和控制演員。但是這裡要註意Group本身其實也是繼承自Actor。

相機我們這裡跳過,以後再說,可以暫時理解成一個控制觀察視角和指標轉化的工具。

當我們擁有一個演員後就可以調用addActor方法加入舞臺。

舞臺可以獲取輸入,但是需要設置。


Gdx.input.setInputProcessor(stage);

下面來個列子,控制一個人物前進。

actor1

控制人物的按鈕:

narrow

將所需的圖片放到assert中

所需資源

新建三個類:

FirstGame,實現接口ApplicationListener

FirstActor,繼承Actor

NarrowButton,繼承Actor

先看一下FirstGame

聲明一個Stage,然後實例化FirstActor和NarrowButton,將二者加入舞臺中,最後設置輸入響應為Stage。


package com.cnblogs.htynkn.listener; 

 

import java.util.Date;  

import java.util.Random; 

 

import javax.microedition.khronos.opengles.GL; 

 

import android.util.Log; 

 

import com.badlogic.gdx.ApplicationListener;  

import com.badlogic.gdx.Gdx;  

import com.badlogic.gdx.graphics.GL10;  

import com.badlogic.gdx.graphics.g2d.BitmapFont;  

import com.badlogic.gdx.scenes.scene2d.Stage;  

import com.cnblogs.htynkn.domain.FirstActor;  

import com.cnblogs.htynkn.domain.NarrowButton; 

 

public class FirstGame implements ApplicationListener { 

 

    private Stage stage;  

    private FirstActor firstActor;  

    private NarrowButton button; 

 

    @Override

    public void create() {  

        stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),  

                true);  

        firstActor = new FirstActor("renwu");  

        button = new NarrowButton("narrow");  

        stage.addActor(firstActor);  

        stage.addActor(button);  

        Gdx.input.setInputProcessor(stage);  

    } 

 

    @Override

    public void dispose() {  

        stage.dispose();  

    } 

 

    @Override

    public void pause() {  

        // TODO Auto-generated method stub 

 

    } 

 

    @Override

    public void render() {  

        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);  

        stage.act(Gdx.graphics.getDeltaTime());  

        stage.draw();  

    } 

 

    @Override

    public void resize(int width, int height) {  

        // TODO Auto-generated method stub 

 

    } 

 

    @Override

    public void resume() {  

        // TODO Auto-generated method stub 

 

    }  

}

再看一下FirstActor。

聲明一個Texture用於繪制。在構造方法中獲取到高度和寬度,以便於後期的hit時間判斷。


package com.cnblogs.htynkn.domain; 

 

import com.badlogic.gdx.Gdx;  

import com.badlogic.gdx.graphics.Texture;  

import com.badlogic.gdx.graphics.g2d.SpriteBatch;  

import com.badlogic.gdx.scenes.scene2d.Actor; 

 

public class FirstActor extends Actor { 

 

    Texture texture; 

 

    @Override

    public void draw(SpriteBatch batch, float parentAlpha) {  

        batch.draw(texture, this.x, this.y);  

    } 

 

    @Override

    public Actor hit(float x, float y) {  

        if (x > 0 && y > 0 && this.height > y && this.width > x) {  

            return this;  

        } else {  

            return null;  

        }  

    } 

 

    @Override

    public boolean touchDown(float x, float y, int pointer) {  

        // TODO Auto-generated method stub  

        return false;  

    } 

 

    @Override

    public void touchDragged(float x, float y, int pointer) {  

        // TODO Auto-generated method stub 

 

    } 

 

    @Override

    public void touchUp(float x, float y, int pointer) {  

        // TODO Auto-generated method stub 

 

    } 

 

    public FirstActor(String name) {  

        super(name);  

        texture = new Texture(Gdx.files.internal("actor1.gif"));  

        this.height = texture.getHeight();  

        this.width = texture.getWidth();  

    }  

}

NarrowButton中代碼繪制部分和上面的以下,主要是有個點擊後控制人物行動的問題。

修改touchDown事件:

通過Group獲取到FirstActor,控制x值。


public boolean touchDown(float x, float y, int pointer) {  

        Actor actor = this.parent.findActor("renwu");  

        actor.x += 10;  

        return false;  

    }

 

 

效果:

ui類1ui類2

到此為止一個最簡單的人物控制我們已經實現瞭。但是這個有實例還有很多可以改進的地方,比如方向按鈕沒有點擊效果,人物沒有移動效果。

我們可以使用Animation來實現。添加一張圖片

actor2

具體的原理我們看一下Animation類:


public class Animation {  

    final TextureRegion[] keyFrames;  

    public float frameDuration; 

 

    /** Constructor, storing the frame duration and key frames.  

     *  

     * @param frameDuration the time between frames in seconds.  

     * @param keyFrames the {@link TextureRegion}s representing the frames. */

    public Animation (float frameDuration, List keyFrames) {  

        this.frameDuration = frameDuration;  

        this.keyFrames = new TextureRegion[keyFrames.size()];  

        for(int i = 0, n = keyFrames.size(); i < n; i++) {  

            this.keyFrames[i] = (TextureRegion)keyFrames.get(i);  

        }  

    }  

     

    /** Constructor, storing the frame duration and key frames.  

     *  

     * @param frameDuration the time between frames in seconds.  

     * @param keyFrames the {@link TextureRegion}s representing the frames. */

    public Animation (float frameDuration, TextureRegion… keyFrames) {  

        this.frameDuration = frameDuration;  

        this.keyFrames = keyFrames;  

    } 

 

    /** Returns a {@link TextureRegion} based on the so called state time. This is the amount of seconds an object has spent in the  

     * state this Animation instance represents, e.g. running, jumping and so on. The mode specifies whether the animation is  

     * looping or not.  

     * @param stateTime the time spent in the state represented by this animation.  

     * @param looping whether the animation is looping or not.  

     * @return the TextureRegion representing the frame of animation for the given state time. */

    public TextureRegion getKeyFrame (float stateTime, boolean looping) {  

        int frameNumber = (int)(stateTime / frameDuration); 

 

        if (!looping) {  

            frameNumber = Math.min(keyFrames.length – 1, frameNumber);  

        } else {  

            frameNumber = frameNumber % keyFrames.length;  

        }  

        return keyFrames[frameNumber];  

    }  

}

可以看出所謂的動畫其實是一張一張的圖片不斷切換(其實所有的動畫都是這個樣子的)。

我們構造一個圖片列表然後根據事件變動不停取出,重新繪制就形成動畫瞭。

註意一下傳入的時間和圖片列表大小的問題,修改FirstActor代碼如下:


package com.cnblogs.htynkn.domain; 

 

import com.badlogic.gdx.Gdx; 

import com.badlogic.gdx.graphics.Texture; 

import com.badlogic.gdx.graphics.g2d.Animation; 

import com.badlogic.gdx.graphics.g2d.SpriteBatch; 

import com.badlogic.gdx.graphics.g2d.TextureRegion; 

import com.badlogic.gdx.scenes.scene2d.Actor; 

 

public class FirstActor extends Actor { 

 

    Texture texture1; 

    Texture texture2; 

    Animation animation; 

    TextureRegion[] walksFrame; 

    float stateTime; 

 

    @Override

    public void draw(SpriteBatch batch, float parentAlpha) { 

        stateTime += Gdx.graphics.getDeltaTime(); 

        TextureRegion currentFrame = animation.getKeyFrame(stateTime, true); 

        batch.draw(currentFrame, this.x, this.y); 

    } 

 

    @Override

    public Actor hit(float x, float y) { 

        Gdx.app.log("INFO", x + " " + this.width); 

        if (x > 0 && y > 0 && this.height > y && this.width > x) { 

            return this; 

        } else { 

            return null; 

        } 

    } 

 

    @Override

    public boolean touchDown(float x, float y, int pointer) { 

        // TODO Auto-generated method stub 

        return false; 

    } 

 

    @Override

    public void touchDragged(float x, float y, int pointer) { 

        // TODO Auto-generated method stub 

 

    } 

 

    @Override

    public void touchUp(float x, float y, int pointer) { 

        // TODO Auto-generated method stub 

 

    } 

 

    public FirstActor(String name) { 

        super(name); 

        texture1 = new Texture(Gdx.files.internal("actor1.gif")); 

        texture2 = new Texture(Gdx.files.internal("actor2.gif")); 

        this.height = texture1.getHeight(); 

        this.width = texture1.getWidth(); 

        TextureRegion region1; 

        TextureRegion region2; 

        region1 = new TextureRegion(texture1); 

        region2 = new TextureRegion(texture2); 

        walksFrame = new TextureRegion[30]; 

        for (int i = 0; i < 30; i++) { 

            if (i % 2 == 0) { 

                walksFrame[i] = region1; 

            } else { 

                walksFrame[i] = region2; 

            } 

        } 

        animation = new Animation(0.25f, walksFrame); 

    } 

}

效果:

2011111423585672

這裡註意一下,為什麼我們要Texture轉為TextureRegion。這是因為在實際開發中的圖片是集成在一起的,比如所有角色要用的圖片都是放在一張圖裡,然後分割截取的,對應的輔助方法TextureRegion.split。

另外我們可以發現NarrowButton和FirstActor中有大量代碼重復瞭,可能有朋友覺得應該提取一下,其實libgdx已經幫我們做瞭,可以參考

ui類

這裡有一些常用的UI控件,估計下一篇可以講到。

 


作者:黃雲坤
出處:http://www.cnblogs.com/htynkn/

發佈留言