commit
ad114a95f8
|
@ -57,8 +57,7 @@ class NavAgent extends Trait {
|
|||
|
||||
orient.subvecs(p, object.transform.loc).normalize;
|
||||
var targetAngle = Math.atan2(orient.y, orient.x) + Math.PI / 2;
|
||||
|
||||
locAnim = Tween.to({ target: object.transform.loc, props: { x: p.x, y: p.y /*, z: p.z*/ }, duration: dist / speed, done: function() {
|
||||
locAnim = Tween.to({ target: object.transform.loc, props: { x: p.x, y: p.y , z: p.z }, duration: dist / speed, done: function() {
|
||||
index++;
|
||||
if (index < path.length) go();
|
||||
else removeUpdate(update);
|
||||
|
|
|
@ -15,6 +15,20 @@ class NavMesh extends Trait {
|
|||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
// recast config:
|
||||
@prop
|
||||
public var cellSize:Float = 0.3; // voxelization cell size
|
||||
@prop
|
||||
public var cellHeight:Float = 0.2; // voxelization cell height
|
||||
@prop
|
||||
public var agentHeight:Float = 2.0; // agent capsule height
|
||||
@prop
|
||||
public var agentRadius:Float = 0.4; // agent capsule radius
|
||||
@prop
|
||||
public var agentMaxClimb:Float = 0.9; // how high steps agents can climb, in voxels
|
||||
@prop
|
||||
public var agentMaxSlope:Float = 45.0; // maximum slope angle, in degrees
|
||||
|
||||
var recast:Recast = null;
|
||||
var ready = false;
|
||||
|
||||
|
@ -33,6 +47,17 @@ class NavMesh extends Trait {
|
|||
|
||||
recast = Navigation.active.recast;
|
||||
recast.OBJDataLoader(b.toString(), function() {
|
||||
|
||||
var settings = [
|
||||
'cellSize' => cellSize,
|
||||
'cellHeight' => cellHeight,
|
||||
'agentHeight' => agentHeight,
|
||||
'agentRadius' => agentRadius,
|
||||
'agentMaxClimb' => agentMaxClimb,
|
||||
'agentMaxSlope' => agentMaxSlope,
|
||||
];
|
||||
recast.settings(settings);
|
||||
|
||||
recast.buildSolo();
|
||||
ready = true;
|
||||
});
|
||||
|
@ -43,7 +68,7 @@ class NavMesh extends Trait {
|
|||
if (!ready) return;
|
||||
recast.findPath(from.x, from.z, from.y, to.x, to.z, to.y, 200, function(path:Array<RecastWaypoint>) {
|
||||
var ar:Array<Vec4> = [];
|
||||
for (p in path) ar.push(new Vec4(p.x, p.z, -p.y));
|
||||
for (p in path) ar.push(new Vec4(p.x, p.z, (p.y + 1.1)));
|
||||
done(ar);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ from arm.props_traits_props import *
|
|||
import arm.utils
|
||||
import arm.write_data as write_data
|
||||
import arm.make as make
|
||||
import json
|
||||
|
||||
def trigger_recompile(self, context):
|
||||
wrd = bpy.data.worlds['Arm']
|
||||
|
@ -306,6 +307,74 @@ class ArmEditBundledScriptButton(bpy.types.Operator):
|
|||
|
||||
return{'FINISHED'}
|
||||
|
||||
class ArmoryGenerateNavmeshButton(bpy.types.Operator):
|
||||
'''Generate navmesh from selected meshes'''
|
||||
bl_idname = 'arm.generate_navmesh'
|
||||
bl_label = 'Generate Navmesh'
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
|
||||
if obj.type != 'MESH':
|
||||
return{'CANCELLED'}
|
||||
|
||||
# TODO: build tilecache here
|
||||
|
||||
# For visualization
|
||||
nav_full_path = arm.utils.get_fp_build() + '/compiled/Assets/navigation'
|
||||
if not os.path.exists(nav_full_path):
|
||||
os.makedirs(nav_full_path)
|
||||
|
||||
nav_mesh_name = 'nav_' + obj.data.name
|
||||
mesh_path = nav_full_path + '/' + nav_mesh_name + '.obj'
|
||||
|
||||
with open(mesh_path, 'w') as f:
|
||||
for v in obj.data.vertices:
|
||||
f.write("v %.4f " % (v.co[0] * obj.scale.x))
|
||||
f.write("%.4f " % (v.co[2] * obj.scale.z))
|
||||
f.write("%.4f\n" % (v.co[1] * obj.scale.y)) # Flipped
|
||||
for p in obj.data.polygons:
|
||||
f.write("f")
|
||||
for i in reversed(p.vertices): # Flipped normals
|
||||
f.write(" %d" % (i + 1))
|
||||
f.write("\n")
|
||||
|
||||
fp_build_name = arm.utils.get_fp_build().rsplit('/')[-1]
|
||||
nav_mesh_path = '/' + fp_build_name + '/compiled/Assets/navigation/' + nav_mesh_name
|
||||
|
||||
buildnavjs_path = arm.utils.get_sdk_path() + '/lib/haxerecast/buildnavjs'
|
||||
|
||||
# append config values
|
||||
nav_config = {}
|
||||
for t in obj.arm_traitlist:
|
||||
# check if trait is navmesh here
|
||||
if len(t.arm_traitpropslist) > 0 and t.class_name_prop == 'NavMesh':
|
||||
for pt in t.arm_traitpropslist: # Append props
|
||||
prop = pt.name.replace(')', '').split('(')
|
||||
name = prop[0]
|
||||
value = float(pt.value)
|
||||
nav_config[name] = value
|
||||
nav_config_json = json.dumps(nav_config)
|
||||
|
||||
args = [arm.utils.get_node_path(), buildnavjs_path, nav_mesh_path, nav_config_json]
|
||||
proc = subprocess.Popen(args)
|
||||
proc.wait()
|
||||
|
||||
navmesh = bpy.ops.import_scene.obj(filepath=mesh_path)
|
||||
navmesh = bpy.context.selected_objects[0]
|
||||
|
||||
navmesh.name = nav_mesh_name
|
||||
navmesh.rotation_euler = (0,0,0)
|
||||
navmesh.location = (obj.location.x,obj.location.y,obj.location.z)
|
||||
navmesh.arm_export = False
|
||||
|
||||
bpy.context.view_layer.objects.active = navmesh
|
||||
bpy.ops.object.editmode_toggle()
|
||||
bpy.ops.mesh.select_all(action='SELECT')
|
||||
bpy.ops.mesh.remove_doubles()
|
||||
bpy.ops.object.editmode_toggle()
|
||||
|
||||
return{'FINISHED'}
|
||||
|
||||
class ArmEditCanvasButton(bpy.types.Operator):
|
||||
'''Edit ui canvas'''
|
||||
bl_idname = 'arm.edit_canvas'
|
||||
|
@ -508,12 +577,17 @@ def draw_traits(layout, obj, is_object):
|
|||
op.is_object = is_object
|
||||
op = row.operator("arm.refresh_scripts")
|
||||
else: # Bundled
|
||||
if item.class_name_prop == 'NavMesh':
|
||||
row = layout.row(align=True)
|
||||
row.alignment = 'EXPAND'
|
||||
op = layout.operator("arm.generate_navmesh")
|
||||
row = layout.row(align=True)
|
||||
row.alignment = 'EXPAND'
|
||||
column = row.column(align=True)
|
||||
column.alignment = 'EXPAND'
|
||||
op = column.operator("arm.edit_bundled_script", icon="FILE_SCRIPT")
|
||||
op.is_object = is_object
|
||||
if not item.class_name_prop == 'NavMesh':
|
||||
op = column.operator("arm.edit_bundled_script", icon="FILE_SCRIPT")
|
||||
op.is_object = is_object
|
||||
op = row.operator("arm.refresh_scripts")
|
||||
|
||||
elif item.type_prop == 'WebAssembly':
|
||||
|
@ -563,6 +637,7 @@ def register():
|
|||
bpy.utils.register_class(ArmTraitListMoveItem)
|
||||
bpy.utils.register_class(ArmEditScriptButton)
|
||||
bpy.utils.register_class(ArmEditBundledScriptButton)
|
||||
bpy.utils.register_class(ArmoryGenerateNavmeshButton)
|
||||
bpy.utils.register_class(ArmEditCanvasButton)
|
||||
bpy.utils.register_class(ArmNewScriptDialog)
|
||||
bpy.utils.register_class(ArmNewCanvasDialog)
|
||||
|
@ -590,6 +665,7 @@ def unregister():
|
|||
bpy.utils.unregister_class(ArmTraitListMoveItem)
|
||||
bpy.utils.unregister_class(ArmEditScriptButton)
|
||||
bpy.utils.unregister_class(ArmEditBundledScriptButton)
|
||||
bpy.utils.unregister_class(ArmoryGenerateNavmeshButton)
|
||||
bpy.utils.unregister_class(ArmEditCanvasButton)
|
||||
bpy.utils.unregister_class(ArmNewScriptDialog)
|
||||
bpy.utils.unregister_class(ArmNewCanvasDialog)
|
||||
|
|
|
@ -434,72 +434,6 @@ class ArmVirtualInputPanel(bpy.types.Panel):
|
|||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
class ARM_PT_NavigationPanel(bpy.types.Panel):
|
||||
bl_label = "Armory Navigation"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
scene = bpy.context.scene
|
||||
if scene == None:
|
||||
return
|
||||
|
||||
layout.operator("arm.generate_navmesh")
|
||||
layout.operator("arm.remove_navmesh")
|
||||
|
||||
class ArmoryGenerateNavmeshButton(bpy.types.Operator):
|
||||
'''Generate navmesh from selected meshes'''
|
||||
bl_idname = 'arm.generate_navmesh'
|
||||
bl_label = 'Generate Navmesh'
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
if obj == None or obj.type != 'MESH':
|
||||
return{'CANCELLED'}
|
||||
|
||||
# Prevent duplicates
|
||||
for t in obj.arm_traitlist:
|
||||
if t.class_name_prop == 'NavMesh':
|
||||
return{'FINISHED'}
|
||||
|
||||
# TODO: build tilecache here
|
||||
|
||||
# Navmesh trait
|
||||
obj.arm_traitlist.add()
|
||||
obj.arm_traitlist[-1].type_prop = 'Bundled Script'
|
||||
obj.arm_traitlist[-1].class_name_prop = 'NavMesh'
|
||||
|
||||
# For visualization
|
||||
# Removed in b28
|
||||
# bpy.ops.mesh.navmesh_make('EXEC_DEFAULT')
|
||||
# obj = context.active_object
|
||||
# obj.hide_render = True
|
||||
# obj.arm_export = False
|
||||
|
||||
return{'FINISHED'}
|
||||
|
||||
class ArmoryRemoveNavmeshButton(bpy.types.Operator):
|
||||
'''Remove generated navmesh from selected mesh'''
|
||||
bl_idname = 'arm.remove_navmesh'
|
||||
bl_label = 'Remove Navmesh'
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
if obj == None or obj.type != 'MESH':
|
||||
return{'CANCELLED'}
|
||||
|
||||
# Navmesh trait
|
||||
for i in range(len(obj.arm_traitlist)):
|
||||
if obj.arm_traitlist[i].class_name_prop == 'NavMesh':
|
||||
obj.arm_traitlist.remove(i)
|
||||
break
|
||||
|
||||
return{'FINISHED'}
|
||||
|
||||
class ArmoryPlayButton(bpy.types.Operator):
|
||||
'''Launch player in new window'''
|
||||
bl_idname = 'arm.play'
|
||||
|
@ -1508,9 +1442,6 @@ def register():
|
|||
bpy.utils.register_class(CleanButtonMenu)
|
||||
bpy.utils.register_class(ArmoryCleanProjectButton)
|
||||
bpy.utils.register_class(ArmoryPublishProjectButton)
|
||||
bpy.utils.register_class(ArmoryGenerateNavmeshButton)
|
||||
bpy.utils.register_class(ArmoryRemoveNavmeshButton)
|
||||
bpy.utils.register_class(ARM_PT_NavigationPanel)
|
||||
bpy.utils.register_class(ArmGenLodButton)
|
||||
bpy.utils.register_class(ARM_PT_LodPanel)
|
||||
bpy.utils.register_class(ArmGenTerrainButton)
|
||||
|
@ -1561,9 +1492,6 @@ def unregister():
|
|||
bpy.utils.unregister_class(CleanButtonMenu)
|
||||
bpy.utils.unregister_class(ArmoryCleanProjectButton)
|
||||
bpy.utils.unregister_class(ArmoryPublishProjectButton)
|
||||
bpy.utils.unregister_class(ArmoryGenerateNavmeshButton)
|
||||
bpy.utils.unregister_class(ArmoryRemoveNavmeshButton)
|
||||
bpy.utils.unregister_class(ARM_PT_NavigationPanel)
|
||||
bpy.utils.unregister_class(ArmGenLodButton)
|
||||
bpy.utils.unregister_class(ARM_PT_LodPanel)
|
||||
bpy.utils.unregister_class(ArmGenTerrainButton)
|
||||
|
|
Loading…
Reference in New Issue