本章繼續上篇文章內容開始帶大家寫代碼,大家要是把這個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就能出來了,其實都是些比較常用簡單的代碼,只要稍微注意了細節就可以了。
感謝閱覽奎斯文章。