Laya Air+Unity3D雙引擎帶你做個天空球3D小遊戲(下篇)

本章繼續上篇文章內容開始帶大家寫代碼,大家要是把這個3d天空球demo學會了再自己豐富一下玩法加點精美UI其實也可以拿去上線發佈哦😀,ok直接開始。

其實在天空球3d遊戲中最主要的就是三個點:

1.玩家要通過控制球體使其左右移動,球體本身要不斷向前滾動

2.攝像機要跟隨球體向前移動

3.通過代碼不斷動態生成球體向前運動所需要的"地板",而兩邊的建築物也要不斷的從下面冒上來向後移動

一、開啓遊戲中的3D物理引擎使球體產生運動:

在Laya中其實只要在類庫中導入3d物理引擎庫,物理引擎就會默認開啓,不像cocos creator那些還要通過代碼主動開啓(記得一定是勾上3d物理引擎的類庫,不是2d),也要勾選上3d的遊戲庫(上篇忘記說了,如果這裏沒有勾選3d場景是沒有辦法加載進來的):

因爲遊戲中只有球體與地板會發生物理碰撞,每個節點掛上剛體與碰撞器組件默認碰撞分組都是0(即會發生碰撞),所以我們在代碼裏就不再設置

二、編寫腳本邏輯

上篇中我們主要創建了三個腳本game_app、player_manager、floor_manager:

game_app:負責控制整個遊戲場景的邏輯

player_manager:負責控制玩家的操作響應

floor_manager:負責生成與刪除地板

我們也加載進了3d遊戲場景,現在我們分別把各個腳本分別掛在對應的節點下

export default class game_app extends Laya.Script{
    constructor(){
        super();
    }
    

    onAwake(){
        this.is_construction_root_moving = false;
        Laya.Scene3D.load("res/LayaScene_game_scene/Conventional/game_scene.ls",Laya.Handler.create(this,this.login_scene3d));
    }

    login_scene3d(scene){
        this.scene = Laya.stage.addChild(scene);
        this.player = this.scene.getChildByName("player");
        this.floor_root =this.scene.getChildByName("floor_root");
        this.camera = this.scene.getChildByName("Main Camera");

        let player_component = this.player.addComponent(player_manager);  //玩家腳本
        let floor_conponent = this.floor_root.addComponent(floor_manager); //地板腳本
    }

}

接下來我們先寫好player_manager,再寫好floor_manager,最後整合到game_app中。

1.首先在player_manager中我們要監聽觸碰事件,並分別註冊三個回調函數,並提前寫好相關的變量:


export default class player_manager extends Laya.Script3D{
    constructor(){
        super();
    }

    onAwake(){
        this.is_playing = false; //是否開啓
        this.rot_x = 0;  //產生球體旋轉效果

        this.go_z = 15;  //用於給剛體向前運動施加的力
        this.go_y = -18;  //用於給操控球體左右運動施加的力

        this.player_is_down = false;  //標識玩家是否按下
        this.rigidbody = this.owner.getComponent(Laya.Rigidbody3D);
        this.rigidbody.angularFactor = new Laya.Vector3(0,0,0);

        Laya.stage.on(Laya.Event.MOUSE_DOWN,this,this.play_down_event);
        Laya.stage.on(Laya.Event.MOUSE_MOVE,this,this.play_move_event);
        Laya.stage.on(Laya.Event.MOUSE_UP,this,this.play_up_event);
    }

    start_game(){
        this.is_playing = true;
    }

    play_down_event(){
        if(this.player_is_down){
            return;
        }

        this.player_is_down = true;
        this.event_pos_x = Laya.MouseManager.instance.mouseX;
    }

    play_move_event(){
        if(!this.player_is_down){
            return;
        }

        this.del_x = Laya.MouseManager.instance.mouseX - this.event_pos_x;
        
        var pos_x = this.del_x/ 30;
        if((this.owner.transform.localPositionX  - pos_x)  <= -2 ||(this.owner.transform.localPositionX  - pos_x)   >= 2){

            return;
        }
        
        this.owner.transform.localPositionX -= pos_x;
        this.event_pos_x = Laya.MouseManager.instance.mouseX;
    }

    play_up_event(){
        if(!this.player_is_down){
            return;
        }

        this.player_is_down = false;
    }

    bind_camera(camera){
        this.camera = camera;
        this.camera_offset = new Laya.Vector3();
        Laya.Vector3.subtract(this.camera.transform.position,this.owner.transform.position,this.camera_offset);
    }

    bind_bg(bg_img){
        this.bg = bg_img;
        this.bg_offset = new Laya.Vector3();
        Laya.Vector3.subtract(this.bg.transform.position,this.camera.transform.position,this.bg_offset);
    }


}

這裏我們通過this.event_pos_x來獲取上一幀的位置,減去當前從而產生偏移,並在play_move_event()中限制玩家控制的範圍,接下來就只要在update中給剛體施加力並改變旋轉就可以了

onUpdate(){
        if(!this.is_playing){
            return;
        }
        var dt = Laya.timer.delta / 1000;
        var speed = dt / 8; 

        if(this.rot_x >= 360){
            this.rot_x -= 360;
        }
        this.rot_x += speed;
        this.owner.transform.rotate(new Laya.Vector3(this.rot_x,0,0));
        this.rigidbody.linearVelocity = new Laya.Vector3(0,this.go_y,this.go_z);
    }

然後我們還要寫上一個攝像機跟隨球體和背景圖跟隨攝像機的方法,然後在重寫的onLateUpdate()中改變位置信息就可以,比較簡單就不解釋太多:

bind_camera(camera){
        this.camera = camera;
        this.camera_offset = new Laya.Vector3();
        Laya.Vector3.subtract(this.camera.transform.position,this.owner.transform.position,this.camera_offset);
    }

bind_bg(bg_img){
        this.bg = bg_img;
        this.bg_offset = new Laya.Vector3();
        Laya.Vector3.subtract(this.bg.transform.position,this.camera.transform.position,this.bg_offset);
    }

onLateUpdate(){
        var c_pos = this.camera.transform.position.clone();
        c_pos.x = this.owner.transform.position.x + this.camera_offset.x /4; 
        c_pos.y = this.owner.transform.position.y + this.camera_offset.y; 
        c_pos.z = this.owner.transform.position.z + this.camera_offset.z; 
        this.camera.transform.position = c_pos;
        
        var bg_pos = this.bg.transform.position.clone();
        bg_pos.x = this.camera.transform.position.x + this.bg_offset.x; 
        bg_pos.y = this.camera.transform.position.y + this.bg_offset.y; 
        bg_pos.z = this.camera.transform.position.z + this.bg_offset.z; 
        this.bg.transform.position = bg_pos;
    }

這裏兩個bind方法我們在game_app中調用就可以了,只要注意一點是上面camera的x我們/4,是因爲攝像機不能完全使用球體的偏移量,要產生一點球體在攝像機範圍內移動的效果。

2.然後就是我們的floor_manager,這個腳本只要負責不斷生成預製體,並當地板移除屏幕範圍後自動消除就行:

export default class floor_manager extends Laya.Script{
    constructor(){
        super();
    }
    onAwake(){
        this.floor_pos = new Laya.Vector3(0,-15,20); //下次生成的地方
        Laya.Sprite3D.load("res/LayaScene_game_scene/Conventional/Cube.lh",Laya.Handler.create(this,function(res){
            this.i = 0;
            Laya.timer.loop(900,this,function(){
                
                var floor_node = this.owner.addChild(Laya.Sprite3D.instantiate(res));
                floor_node.transform.localPosition = this.floor_pos;
                this.floor_pos.x =  (Math.random() - 0.5 ) * 3;
                this.floor_pos.y -=8;
                this.floor_pos.z +=12;
                
            })    
            Laya.timer.loop(1300,this,function(){
                this.owner.getChildAt(0).removeSelf();
            })
        }));
    }

    
}

3.最後就是在game_app中整合進來就可以了,爲了直觀,這裏直接貼上所有代碼,解釋寫在註釋中:

import player_manager from "./player_manager";
import floor_manager from "./floor_manager";
export default class game_app extends Laya.Script{
    constructor(){
        super();
    }
    

    onAwake(){
        this.is_construction_root_moving = false;
        this.construction_y = 0;
        Laya.Scene3D.load("res/LayaScene_game_scene/Conventional/game_scene.ls",Laya.Handler.create(this,this.login_scene3d));
    }

    login_scene3d(scene){
        this.scene = Laya.stage.addChild(scene);
        this.player = this.scene.getChildByName("player");
        this.floor_root =this.scene.getChildByName("floor_root");
        this.camera = this.scene.getChildByName("Main Camera");

        var bg = this.scene.getChildByName("bg");
        let player_component = this.player.addComponent(player_manager);
        player_component.bind_camera(this.camera);  //攝像機圖跟隨
        player_component.bind_bg(bg); //背景圖跟隨
        player_component.start_game();    
        Laya.Sprite3D.load("res/LayaScene_game_scene/Conventional/construction_root.lh",Laya.Handler.create(this,this.create_construction));
    }

    create_construction(res){  //產生兩邊建築物 
        this.construction_root = this.scene.addChild(Laya.Sprite3D.instantiate(res));
        Laya.timer.loop(2000,this,function(){
            
             this.construction_root.transform.localPositionZ =  this.player.transform.localPositionZ + 3;
            this.construction_root.transform.localPositionY =  this.player.transform.localPositionY - 15;
            this.is_construction_root_moving = true;
        })
    }
    
    onUpdate(){
        if(!this.is_construction_root_moving){
            return;
        } 
        var dt = Laya.timer.delta / 1000;
        var speed = dt * 10;
        //循環改變地板位置
        if(this.construction_y >= 35){
            this.construction_y = 0;
        }
        this.construction_root.transform.localPositionY += speed;
        this.construction_y += speed;
    }  
}

基本上我們的3d天空球demo就能出來了,其實都是些比較常用簡單的代碼,只要稍微注意了細節就可以了。

 

感謝閱覽奎斯文章。

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