基于SceneForm实现子弹射击(绘制子弹运行轨迹)
基于SceneForm实现的子弹射击(绘制子弹运行轨迹)
Sceneform框架很强大,不了解Sceneform的时候,觉得要想做3D场景需要会OpenGL,而OpenGL的学习曲线很陡;接触到这个框架之后觉得小白也可以很快上手,甚至可以实现第一人称射击的效果
注:自己学习SceneForm有一段时间了,不过没有发现模拟重力场的接口,不知道是不是自己漏掉了
模拟射击效果的思路其实很简单
1、加载一个子弹模型
2、规划子弹由近及远的轨迹
3、绘制子弹的运行轨迹
子弹运行轨迹的逻辑代码;代码中涉及的CleanArFragment在之前的《ARCore的SceneForm框架在没有Plane情况下的绘制3D模型》已经给出;另外需要自行提供一个纹理图片,即代码中的R.drawable.texture。
classMainActivity:AppCompatActivity(){
vararFragment:CleanArFragment?=null
varcamera:Camera?=null
varsize=Point();//屏幕尺寸,控制子弹发射的初始位置
varbullet:ModelRenderable?=null
varscene:Scene?=null
valSHOT=0x1101//绘制过程轨迹信号
valSHOT_OVER=0x1102//清除子弹模型信号
varhandler=object:Handler(){
overridefunhandleMessage(msg:Message)
{
if(msg.what==SHOT){//绘制移动过程中的轨迹
varcurrentStatus=msg.objasCurrentStatus
currentStatus.node.worldPosition=currentStatus.status
}elseif(msg.what==SHOT_OVER){//一次射击完成,清除屏幕的子弹
varnode=msg.objasNode
scene!!.removeChild(node)
}
}
}
overridefunonCreate(savedInstanceState:Bundle?){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//获取屏幕尺寸
valdisplay=windowManager.defaultDisplay
display.getRealSize(size)
arFragment=this.supportFragmentManager.findFragmentById(R.id.arFragment)asCleanArFragment
arFragment!!.arSceneView.planeRenderer.isEnabled=false//禁止sceneform框架的平面绘制
scene=arFragment!!.arSceneView.scene
camera=scene!!.camera
initbullet()
shootButton.setOnClickListener(listener)
}
varlistener:View.OnClickListener=object:View.OnClickListener{
overridefunonClick(v:View?){
shoot()
}
}
@TargetApi(Build.VERSION_CODES.N)
//初始化子弹模型
privatefuninitbullet(){
Texture.builder().setSource(this@MainActivity,R.drawable.texture).build()
.thenAccept(
{texture->
MaterialFactory.makeOpaqueWithTexture(this@MainActivity,texture)
.thenAccept{material->
//设置子弹模型为球体
bullet=ShapeFactory.makeSphere(0.1f,Vector3(0f,0f,0f),material)}
}
)
}
privatefunshoot(){
//从屏幕发出的射线,对应子弹的运行轨迹
varray=camera!!.screenPointToRay(size.x/2f,size.y/2f);
varnode=Node()//子弹节点
node.renderable=bullet//子弹节点加载子弹模型
scene!!.addChild(node)
Thread(object:Runnable{
overridefunrun(){
//子弹射击过程中的轨迹,子线程处理轨迹事件,主线程改变轨迹位置
for(iin1..200){//子弹射程20m
varstepLen=i;
varcurrentPoint=ray.getPoint(stepLen*0.1f)
varmsg=handler.obtainMessage()
msg.what=SHOT
msg.obj=CurrentStatus(node,currentPoint)
handler.sendMessage(msg)
}
//子弹超出距离后,从屏幕清除掉
varmsg=handler.obtainMessage()
msg.what=SHOT_OVER
msg.obj=node
handler.sendMessage(msg)
}
}).start()
}
//子线程和主线程穿点的数据类
dataclassCurrentStatus(varnode:Node,varstatus:Vector3)
}
界面布局
实现效果如下,因为动图的偏差,子弹不是很清晰,子弹由中心的红色十字向远处射击
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。