赞
踩
公司要开始做小游戏了,经过研究讨论之后决定采用Laya作为开发引擎,本身是做Unity3D开发的,学习成本很低,Laya的编程方式和Unity很相似,对Unity开发人员来说没有什么难度,从这篇文章开始就记录一下学习以Laya制作demo。
前去Laya官网下载对应版本的Unity导出插件,在Unity中搭建好场景,并一键导出。(注意Laya并不支持Unity的材质,需要将Unity的材质转换成Laya的材质)
Laya 的资源一般存放在工程路径下bin/res Unity导出的场景文件也放在这个场景即可。
Laya的开发方式和Unity一致,因此创建一个GameStart脚本加载3D场景,并将3D场景添加至舞台。因为舞台上存在着一些UI,因此我们需要将3D场景加载到第0号节点,以免3D场景遮挡了其它的UI
onAwake(): void{ Laya3D.init(0, 0); Laya.Scene3D.load("res/LayaScene_Main/Conventional/Main.ls",Laya.Handler.create(this,this.onSceneLoadComplete)); Laya.stage.on(AppConst.MoveColumn,this,this.moveColumn); Laya.stage.on(AppConst.CreatePrticle,this,this.onSpawnPrticle) Laya.stage.on(AppConst.RePlayGame,this,this.onRePlayGame) } onSceneLoadComplete(scene):void { //加载完成获取到了Scene3d Laya.stage.addChildAt(scene,0); this.scene=scene; //加载完成获取到了Scene3d Laya.stage.addChildAt(scene,0); this.scene=scene; //获取摄像机 var camera = scene.getChildByName("Main Camera"); //清除摄像机的标记 camera.clearFlag = Laya.BaseCamera.CLEARFLAG_SKY; camera.addComponent(CameraFollow) var parent=scene.getChildByName("Parent") this.column=parent.getChildByName("Column") parent.addComponent(Rotation); var player=scene.getChildByName("Player") //拖尾特效 var trail=scene.getChildByName("TrailRender") player.addChild(trail); trail.transform.localPosition=new Laya.Vector3();//默认为(0,0,0) player.addComponent(PlayerController) var platform=parent.getChildByName("Platform"); platform.active=false this.owner.addComponent(SpawnPlatform).init(platform,parent); var particle=scene.getChildByName("Particle") this.particle=Laya.Sprite3D.instantiate(particle,scene); }
实现让圆柱跟随拖拽旋转逻辑很简单,只需要捕获鼠标按下、拖动以及抬起三个事件,做相应的逻辑处理即可。
注意 Laya.stage.on(Laya.Event.MOUSE_OUT,this,this.onStageMouseUp)
在舞台外鼠标抬起事件无法通过onStageMouseUp
获取,因此需要监听全局的鼠标抬起事件。
import AppConst from "./AppConst"; export default class Rotation extends Laya.Script { lastMouseX:any isMouseDown:boolean isGameOver:boolean constructor(){ super(); this.lastMouseX=0; this.isMouseDown=false this.isGameOver=false; } /*组件被激活后执行,此时所有节点和组件均已创建完毕,次方法只执行一次*/ onAwake(): void{ //鼠标移出后需要处理为在舞台上抬起鼠标, Laya.stage.on(Laya.Event.MOUSE_OUT,this,this.onStageMouseUp) Laya.stage.on(AppConst.GameOver,this,this.onGameOver); Laya.stage.on(AppConst.RePlayGame,this,this.onRePlayGame) } onRePlayGame():void { this.isGameOver=false; (this.owner as Laya.Sprite3D).transform.localRotationEulerY=0; } onGameOver():void { this.isGameOver=true; this.isMouseDown=false; } onStageMouseDown(e):void { if(this.isGameOver) return; this.lastMouseX=e.stageX;//鼠标在舞台上X轴位置 this.isMouseDown=true } onStageMouseMove(e):void { if(this.isGameOver) return; if(this.isMouseDown) { var deltaX=e.stageX-this.lastMouseX; (this.owner as Laya.Sprite3D).transform.rotate(new Laya.Vector3(0,deltaX/5,0),true,false); this.lastMouseX=e.stageX; } } onStageMouseUp(e):void { if(this.isGameOver) return; this.lastMouseX=0; this.isMouseDown=false; } }
import AppConst from "./AppConst"; export default class PlayerController extends Laya.Script3D { constructor(){ super(); } player:Laya.CharacterController; physics:Laya.PhysicsSimulation; ray:Laya.Ray; hitResult:Laya.HitResult isGameOver:boolean; throughCount:number; /*组件被激活后执行,此时所有节点和组件均已创建完毕,次方法只执行一次*/ onAwake(): void{ //获取场景物理模拟器用于射线碰撞 this.physics=(this.owner.parent as Laya.Scene3D).physicsSimulation; //创建射线 this.ray=new Laya.Ray(new Laya.Vector3(),new Laya.Vector3(0,-1,0)); this.hitResult=new Laya.HitResult(); //穿件角色控制 this.player=this.owner.addComponent(Laya.CharacterController); var collider=new Laya.SphereColliderShape(0.2) this.player.colliderShape=collider; this.player.fallSpeed=50;//下落速度 this.player.jumpSpeed=7;//弹回速度 this.isGameOver=false; this.throughCount=0; Laya.timer.frameLoop(1,this,this.RayCast) Laya.stage.on(AppConst.RePlayGame,this,this.onRePlayGame) } onRePlayGame():void { (this.owner as Laya.Sprite3D).transform.localPositionY=0; this.isGameOver=false; } RayCast(): void { if(this.isGameOver) return; this.ray.origin=(this.owner as Laya.MeshSprite3D).transform.position; if(this.throughCount>=3&&this.physics.rayCast(this.ray,this.hitResult,0.2)) { var col=this.hitResult.collider as Laya.PhysicsCollider this.setPlatform(col.owner.parent) } if(this.physics.rayCast(this.ray,this.hitResult,0.15)) { var col=this.hitResult.collider as Laya.PhysicsCollider if(col.owner.name=="Obstacle") { this.throughCount=0; this.isGameOver=true; console.log("GameOver",col.owner.parent) Laya.stage.event(AppConst.GameOver) return; } else if(col.owner.name=="Bar") { // 碰到平台,播放一个粒子特效 Laya.stage.event(AppConst.CreatePrticle,(col.owner as Laya.Sprite3D).transform.position); this.player.jump(); this.throughCount=0; } else { col.owner.parent.removeSelf(); //回收 Laya.Pool.recover("Platform",col.owner.parent) Laya.stage.event(AppConst.MoveCamera,[(col.owner.parent as Laya.Sprite3D).transform.localPositionY,col.owner.parent]) //生成一个平台 Laya.stage.event(AppConst.CreatePlatform); Laya.stage.event(AppConst.MoveColumn); this.throughCount++;//计算通过个数,生成无敌模式 if(this.throughCount>=3) { Laya.stage.event(AppConst.AddScore,3); } else { Laya.stage.event(AppConst.AddScore,1); } } } } setPlatform(platform):void { //第一个平台需要特殊处理 for(var i=0;i<platform.numChildren;i++) { var child=platform.getChildAt(i) child.meshRenderer.material._ColorR=0; child.meshRenderer.material._ColorG=0; child.meshRenderer.material._ColorB=1; if(child.name!="Empty") child.name="Bar"; } } }
import AppConst from "./AppConst"; export default class SpawnPlatform extends Laya.Script { initPosY:any spawnCount:any prefab:Laya.Sprite3D parent:Laya.Sprite3D platformArr:Laya.Sprite3D[]=[]; constructor(){ super(); this.initPosY=-1; this.spawnCount=0 } init(prefab,parent):void{ this.prefab=prefab; this.parent=parent; this.initPosY=-1; this.spawnCount=0 for(var i=0;i<10;i++) { this.spawn(prefab,parent) } Laya.stage.on(AppConst.CreatePlatform,this,this.spawn) Laya.stage.on(AppConst.RePlayGame,this,this.onRePlayGame) } onRePlayGame():void { this.platformArr.forEach(element => { if(element.displayedInStage) { element.removeSelf(); Laya.Pool.recover("Platform",element) } }); this.init(this.prefab,this.parent); } spawn(prefab,parent):void { //Laya 对象池 var temp=Laya.Pool.getItemByCreateFun("Platform",this.createFun,this) //var temp=Laya.Sprite3D.instantiate(prefab,parent) this.parent.addChild(temp) temp.active=true temp.transform.localPosition=new Laya.Vector3(0,this.initPosY-(1.5*this.spawnCount),0); this.setPlatform(temp); this.platformArr.push(temp); this.spawnCount++; } //如果对象池没有缓存对象,则调用此方法创建 createFun():any { var temp=Laya.Sprite3D.instantiate(this.prefab,this.parent); return temp } //随机设置平台的空位置 setPlatform(platform):void { //还原为默认初始状态 if(this.spawnCount==0) { //第一个平台需要特殊处理 for(var i=0;i<platform.numChildren;i++) { var child=platform.getChildAt(i) child.getComponent(Laya.PhysicsCollider).isTrigger=false; child.meshRenderer.material._ColorR=0; child.meshRenderer.material._ColorG=0; child.meshRenderer.material._ColorB=0; child.meshRenderer.enable=true child.name="Bar" if(i==0||i==1) { child.name="Empty" child.meshRenderer.enable=false //child.getComponent(Laya.PhysicsCollider).isTrigger=true; } else { child.meshRenderer.enable=true; child.getComponent(Laya.PhysicsCollider).isTrigger=false; } } return; } var emptyCount=0; var obstacleValue=Math.floor(this.getRandom(0,platform.numChildren-1)) for(var i=0;i<platform.numChildren;i++) { var child=platform.getChildAt(i) //因为有缓存池的存在,因此需要重置 child.getComponent(Laya.PhysicsCollider).isTrigger=false; child.meshRenderer.material._ColorR=0; child.meshRenderer.material._ColorG=0; child.meshRenderer.material._ColorB=0; child.meshRenderer.enable=true child.name="Bar" //控制空位置不超过4个 if(obstacleValue!=i&&emptyCount<3&&this.getRandom(0,10)>8) { child.meshRenderer.enable=false; //child.getComponent(Laya.PhysicsCollider).isTrigger=true; child.name="Empty"; emptyCount++; } else if(obstacleValue==i) { child.meshRenderer.material._ColorR=1; child.meshRenderer.material._ColorG=0; child.meshRenderer.material._ColorB=0; child.name="Obstacle" } } if(emptyCount==0) { // var child=platform.getChildAt(0) child.name="Empty" child.meshRenderer.material._ColorR=0; child.meshRenderer.material._ColorG=0; child.meshRenderer.material._ColorB=0; child.meshRenderer.enable=false // child.getComponent(Laya.PhysicsCollider).isTrigger=true; } } getRandom(min,max){ var delta=max-min; var randomValue=Math.random()*delta return min+randomValue }
当小球每次下落之后我们需要将摄像机和圆柱跟随移动,避免穿帮。Laya也很贴心的封装了类似DOTween的功能插件。
//相机移动
onCameraFollw(posY,obj):void
{
Laya.Tween.to( (this.owner as Laya.Camera).transform,{localPositionY:posY},700)
}
//柱子
moveColumn(obj):void
{
(this.column as Laya.Sprite3D).transform.localPositionY-=1.5;
}
Laya源码工程以上传,可下载查看
对于本身从事Unity开发的人员来说,学习用Laya来做小游戏上手很快,但是也有很多坑需要趟。例如在此demo中,如果采用Laya提供的onUpdate方法中进行射线检测会出现直接穿过平台而不销毁(射线碰撞没有检测到),而采用Laya提供的帧函数方法Laya.timer.frameLoop(1,this,this.RayCast)
则不会出现,目测是onUpdate可能没有完全的按照每一帧来刷新,需要学习做更多的项目,熟悉度高了才更快的迭代项目。当量变达到一定程度后也会发生质变。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。