Skip to content

Instantly share code, notes, and snippets.

@kergalym
Last active January 4, 2022 23:11
Show Gist options
  • Save kergalym/f09098c03b752d24448a981a32849a3f to your computer and use it in GitHub Desktop.
Save kergalym/f09098c03b752d24448a981a32849a3f to your computer and use it in GitHub Desktop.
P3D Archery Code Fragment
self.arrows = []
self.dropped_arrows = []
self.arrow_brb_in_use = None
self.arrow_ref = None
self.target_np = None
self.arrow_nums_in_inv = 20
self.prepare_arrows(self.bow, "bow_arrow", spine_joint)
self.draw_bow_is_done = 0
taskMgr.add(self.cursor_state_task, "cursor_state_task")
taskMgr.add(self.arrow_hit_check, "arrow_hit_check")
taskMgr.add(self.charge_arrow_task, "charge_arrow_task")
taskMgr.add(self.arrow_fly_task, "arrow_fly_task")
def draw_bow_anim_state(self, actor, state, loop):
if isinstance(state, str) and isinstance(loop, int):
self.stateControl = actor.getAnimControl(state)
if self.stateControl and not self.stateControl.isPlaying():
if self.draw_bow_is_done == 0:
actor.play(state)
self.draw_bow_is_done = 1
def cursor_state_task(self, task):
if (self.has_weapon['bow']
and not self.key_map["melee_attack"]
and self.key_map["archery_attack"]):
self.cursor_ui.show()
base.camera.set_x(0.5)
base.camera.set_y(-2)
self.is_aiming = True
if (self.has_weapon['bow']
and not self.key_map["melee_attack"]
and not self.key_map["archery_attack"]
and self.is_aiming):
self.cursor_ui.hide()
base.camera.set_x(0)
base.camera.set_y(self.cam_y_back_pos)
self.is_aiming = False
return task.cont
def prepare_arrows(self, bow, arrow_name, joint):
if bow and arrow_name and isinstance(arrow_name, str) and joint:
for i in range(self.arrow_nums_in_inv):
arrow = base.loader.loadModel('{0}/Assets/Weapons/bow_arrow.egg'.format(self.game_dir))
arrow.set_name(arrow_name)
arrow.reparent_to(joint)
arrow.set_pos(-10, 7, -12)
arrow.set_hpr(91.55, 0, 0)
arrow.set_scale(100)
arrow.set_python_tag("power", 0)
arrow.set_python_tag("ready", 0)
arrow.set_python_tag("shot", 0)
arrow.set_python_tag("owner", "player")
self.arrows.append(arrow)
def return_arrow_back(self, joint):
if self.arrow_ref and joint:
if self.arrow_ref.get_python_tag("ready") == 0:
self.arrow_ref.reparent_to(joint)
self.arrow_ref.set_pos(-10, 7, -12)
self.arrow_ref.set_hpr(91.55, 0, 0)
self.arrow_ref.set_scale(100)
self.arrow_ref.set_python_tag("power", 0)
self.arrow_ref.set_python_tag("ready", 0)
self.arrow_ref.set_python_tag("shot", 0)
self.arrows.append(self.arrow_ref)
if self.arrow_brb_in_use:
self.world.remove_rigid_body(self.arrow_brb_in_use.node())
self.arrow_brb_in_use.remove_node()
def prepare_arrow_for_shoot(self, bow):
if bow:
if len(self.arrows) < 1:
return
# Remove arrow from inv and prepare it for use
arrow = self.arrows.pop(0)
arrow.reparent_to(bow)
arrow.set_pos(0.04, -0.01, -0.01)
arrow.set_hpr(0, 2.86, 0)
arrow.set_scale(1)
# Create arrow collider
shape = BulletBoxShape(Vec3(0.05, 0.5, 0.05))
body = BulletRigidBodyNode('Arrow')
arrow_rb_np = NodePath(body)
arrow_rb_np.wrt_reparent_to(bow)
arrow_rb_np.set_pos(arrow.get_pos())
arrow_rb_np.set_hpr(arrow.get_hpr())
arrow_rb_np.set_scale(arrow.get_scale())
arrow.wrt_reparent_to(arrow_rb_np)
arrow_rb_np.node().add_shape(shape)
arrow_rb_np.node().set_mass(2.0)
# Player and its owning arrow won't collide with each other
arrow_rb_np.set_collide_mask(BitMask32.bit(0))
# Enable CCD
arrow_rb_np.node().set_ccd_motion_threshold(1e-7)
arrow_rb_np.node().set_ccd_swept_sphere_radius(0.50)
arrow_rb_np.node().set_kinematic(True)
self.world.attach_rigid_body(arrow_rb_np.node())
self.arrow_brb_in_use = arrow_rb_np
self.arrow_ref = arrow
def charge_arrow_task(self, task):
if (self.key_map["melee_attack"]
and self.key_map["archery_attack"]):
if self.arrow_brb_in_use:
power = self.arrow_ref.get_python_tag("power")
power += 1
self.arrow_ref.set_python_tag("power", power)
self.arrow_ref.set_python_tag("ready", 1)
if not self.key_map["melee_attack"] and self.key_map["archery_attack"]:
if self.arrow_brb_in_use and self.arrow_ref.get_python_tag("ready") == 1:
if self.arrow_ref.get_python_tag("shot") == 0:
self.bow_shoot()
if (not self.key_map["melee_attack"]
and not self.key_map["archery_attack"]):
if self.draw_bow_is_done == 1:
self.draw_bow_is_done = 0
self.korlan.stop("draw_bow")
return task.cont
def bow_shoot(self):
if self.arrow_brb_in_use and self.target_pos and self.hit_target:
name = self.hit_target.get_name()
self.target_np = render.find("**/{0}".format(name))
self.arrow_ref.set_python_tag("shot", 1)
# Get Bullet Rigid Body wrapped arrow
self.arrow_brb_in_use.node().set_kinematic(False)
self.arrow_brb_in_use.wrt_reparent_to(render)
# We record arrows which have been shot
self.dropped_arrows.append(self.arrow_brb_in_use)
Sequence(Wait(1), Func(self.prepare_arrow_for_shoot, self.bow)).start()
# Destroy dropped arrows after 200 seconds which are 3 minutes
taskMgr.do_method_later(200, self.destroy_arrow, 'destroy_arrow')
def arrow_fly_task(self, task):
dt = globalClock.getDt()
if self.arrow_brb_in_use:
power = self.arrow_ref.get_python_tag("power")
if power and self.arrow_ref.get_python_tag("shot") == 1:
self.arrow_brb_in_use.set_x(self.arrow_brb_in_use, -power * dt)
return task.cont
def arrow_hit_check(self, task):
if self.arrow_brb_in_use:
mouse_watch = base.mouseWatcherNode
if mouse_watch.has_mouse():
pos_mouse = base.mouseWatcherNode.get_mouse()
pos_from = Point3()
pos_to = Point3()
base.camLens.extrude(pos_mouse, pos_from, pos_to)
pos_from = self.render.get_relative_point(base.camera, pos_from)
pos_to = self.render.get_relative_point(base.camera, pos_to)
self.raytest_result = self.world.ray_test_closest(pos_from, pos_to)
if self.raytest_result.get_node() \
and "Ground" not in str(self.raytest_result.get_node().get_name()) \
and "Korlan" not in str(self.raytest_result.get_node().get_name()):
self.hit_target = self.raytest_result.get_node()
self.target_pos = self.raytest_result.get_hit_pos()
if self.hit_target:
self.target_test_ui.setText(self.hit_target.get_name())
else:
self.target_test_ui.setText("")
if self.arrow_brb_in_use:
self.world.contactTest(self.hit_target)
if self.world.contactTest(self.hit_target).getNumContacts() > 0:
if self.arrow_ref.get_python_tag("ready") == 1:
if self.target_np:
self.arrow_brb_in_use.wrt_reparent_to(self.target_np)
self.reset_arrow_charge()
return task.cont
def reset_arrow_charge(self):
if self.arrow_brb_in_use:
self.arrow_ref.set_python_tag("power", 0)
def destroy_arrow(self, task):
if len(self.arrows) < 1:
return
if self.dropped_arrows:
for arrow_rb in self.dropped_arrows:
self.world.removeRigidBody(arrow_rb.node())
arrow_rb.remove_node()
return task.done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment