HeroEngine Forums
Welcome, Guest. Please login or Register for HeroCloud Account.
Pages: 1 [2]

Author Topic: [Resolved] Raycast3D Usage  (Read 4649 times)

DragonFist

  • General Accounts
  • *
  • Posts: 140
    • View Profile
Re: Raycast3D Usage
« Reply #15 on: Jul 09, 12, 06:33:53 PM »

Yeah.  Just an idea at the moment.  Not even sure it would be useful, if the problem comes from a bad reported vector from the camera.
Logged

Jrome90

  • General Accounts
  • *
  • Posts: 330
    • View Profile
Re: Raycast3D Usage
« Reply #16 on: Jul 09, 12, 06:39:22 PM »

Yeah.  Just an idea at the moment.  Not even sure it would be useful, if the problem comes from a bad reported vector from the camera.

Please read this: https://community.heroengine.com/forums/index.php/topic,164.msg580.html#msg580
Logged

DragonFist

  • General Accounts
  • *
  • Posts: 140
    • View Profile
Re: Raycast3D Usage
« Reply #17 on: Jul 09, 12, 06:46:34 PM »

Thanks, that rules out using those for this purpose unless I had a means of converting the vector to world.

Still leaves me with the problem of stray rays.  I'm going to probably move on to other systems for the time being, but I'll have to solve this at some point as it gives a bad user experience if selection occasionally randomly changes, especially if it occurs at the moment of using an attack.
« Last Edit: Jul 09, 12, 07:39:16 PM by DragonFist »
Logged

HE-Cooper

  • *****
  • Posts: 2221
    • View Profile
Re: Raycast3D Usage
« Reply #18 on: Jul 09, 12, 07:03:02 PM »

The FPS ref uses a set of rays for shooting and Alex did a nicely tuned set for the axe swing as well, so that might help you. And the space ref uses the raycast from cursor function I think.
Logged

Jrome90

  • General Accounts
  • *
  • Posts: 330
    • View Profile
Re: Raycast3D Usage
« Reply #19 on: Jul 09, 12, 07:57:21 PM »

Alex did a nicely tuned set for the axe swing as well, so that might help you.

It sure seems much better than what I used :)
With some tweaking it should work
Thanks

Just in case anybody is interested, here is a better way to do what the code I posted on the first page does. (Does that make any sense?)

It is much easier to read
Except I can't take credit for this.
Credit goes to HE-Alex(Is that correct?). I just tweaked it a little
Code: [Select]
method RaycastSelection()
  theTimer as NodeRef of Class genericTimer = CreateNodeFromClass("genericTimer")
  thetimer.myTimer.script = SYSTEM.EXEC.THISSCRIPT
  theTimer.myTimer.fireRate = 00:00:01.000
  thetimer.myTimer.start()
.
function myTimer_tick()
  timer as NodeRef of Class genericTimer = me

  if $BASECLIENT._GetAreaName() <> "Character Selection" //Quick way to just stop the script if we go to the character selection area
    cam as NodeRef = GetActiveCamera()
    start_pos as Vector3
    GetNodePosition(cam,start_pos)
    rotation as Vector3 = GetNodeRotation( cam )
 
 
    distance as Float = 20
    intercept as Vector3 = (0,0,0)
    meshName as String = ""
   
 
    adjusted_rotation as Vector3 = rotation
    adjusted_rotation.x *= -1
    adjusted_rotation.y = MungeHeadingDegrees( adjusted_rotation.y )
    adjusted_rotation.y *= -1
 
    direction as Vector3 = RotateVector( (0,0,-1), adjusted_rotation )
 
    excluded_nodes as List of NodeRef
    add back SYSTEM.INFO.PLAYERCHARACTER to excluded_nodes
 
 
    num_rays as Integer = 6
    angle as Vector3 = (0.0, 5.0, 0.0)
    rotation_offset as Vector3 = ((angle.x / 2) * -1, angle.y * -1, (angle.z / 2) * -1)
   
    loop i from 1 to num_rays
        rotation_offset.y += (angle.y / num_rays)
     
     
        adjusted_rotation.x = (rotation.x + rotation_offset.x)
        adjusted_rotation.x *= -1
        adjusted_rotation.y = (rotation.y + rotation_offset.y)
        adjusted_rotation.y = MungeHeadingDegrees( adjusted_rotation.y )
        adjusted_rotation.y *= -1
     
        direction = RotateVector( (0,0,-1), adjusted_rotation )
     
     
     
        rotation_offset.x += angle.x / num_rays
        rotation_offset.y += angle.y / num_rays
        rotation_offset.z += angle.z / num_rays
 
      var character  = Raycast3D(start_pos,direction,excluded_nodes,distance,Intercept,meshName)
      if character <> None
        where character
          is kindof _NonPlayerCharacter
         
            $Debug._drawDebugRay(start_pos, Intercept, 0.02, "00FF00", "00FF00", 0.3, false)
            sendchat("Your Character sees "+ character.GetMyName(),"GAME")
          .
          is kindof HBNode
            $Debug._drawDebugRay(start_pos, Intercept, 0.02, "00FF00", "00FF00", 0.3, false)

          .
          default
            $Debug._drawDebugRay(start_pos, Intercept, 0.02, "00FF00", "00FF00", 0.3, false)
          .
        .
      else
      .
    .
  else
    timer.myTimer.stop()
    me.Stop_Selection()
  .
.
method Stop_Selection()
  DestroyNode(me)
.
« Last Edit: Jul 10, 12, 03:27:16 AM by Jrome90 »
Logged

DragonFist

  • General Accounts
  • *
  • Posts: 140
    • View Profile
Re: Raycast3D Usage
« Reply #20 on: Jul 10, 12, 05:48:00 AM »

Below is my current implementation as a targeting system.  Definitely not getting the random, stray raycasts anymore and that is good.  I'm sure I can clean this up a bit more (excuse the various commented out bits as I played with different settings and debug ray draws.

In addition, I did another video showing it in action, this time with the default attack actions wired up to the mouse buttons to get a little game-play going which can be viewed here (click for youtube video).


method oncreate()
  
me.ZA_targetTimer.script SYSTEM.EXEC.THISSCRIPT
  me
.ZA_targetTimer.fireRate 00:00:00.001
  me
.ZA_targetTimer.start()
 
// println("targetTimer Started")
.

function 
ZA_targetTimer_tick()
 
// println("Getting Target")
  
me.GetCameraTarget()
.

method StartDelayedTargetDrop()
  if 
me.Za_targetDropDelayTimer.timerState == ON
    me
.Za_targetDropDelayTimer.stop()
  .
  
me.Za_targetDropDelayTimer.fireRate 00:00:00.100
  me
.Za_targetDropDelayTimer.script None
  me
.Za_targetDropDelayTimer.start()
.

method StopDelayedTargetDrop()
  
me.Za_targetDropDelayTimer.stop()
  
//destroynode(me)
.
method Za_targetDropDelayTimer_TICK()
  
//---------------------------------------------------------------
  // When this timer fires, Drop the current target
  //---------------------------------------------------------------
//    println( "Stopping previous target: " )
  
if me.E_TargetingFX != 0
//    println( "Stopping previous target: " + me.E_TargetingFX )
    
sb as NodeRef of Class GUIControl FindGUIControlByName(0,"game.targetStatusBar")
    if 
sb != None
      DestroyNode
(sb)
    .
    
me.E_StopTargetme.E_TargetingFX )
    
me.E_TargetID 0
      
var acct GetAccountID()
      
call server E_playerAccountClassMethods:ClearClickTarget(acct)
  .
.


remote method E_UpdateTargetCircletargetID as ID )
//  println( "Update targeting circle." )
  
if me.E_TargetingFX != 0
//    println( "Stopping previous target: " + me.E_TargetingFX )
    
sb as NodeRef of Class GUIControl FindGUIControlByName(0,"game.targetStatusBar")
    if 
sb != None
      DestroyNode
(sb)
    .
    
me.E_StopTargetme.E_TargetingFX )
  .
  
target as NodeRef targetID
  
if target != None
//    println( "Setting new target: " + targetID )
    
me.E_TargetID targetID
    caster 
as Class _Target
    caster
._tgtID targetID
    me
.E_TargetingFX $FXSYSTEM.PlayFxFromSpec4castercaster )
    
statusbar as NodeRef of Class E_targetStatusBar CreateNodeFromPrototype("E_targetStatusBar")
    
statusbar.name "targetStatusBar"
    
statusbar.build true
    realtarget 
as NodeRef of Class E_CommonCharacter
    where target 
      is kindof _PlayerAccount
        realtarget 
target.GetMyCharacter()
      .
      default
        
realtarget target
      
.
    .
    if 
realtarget != None
      AddAssociation
(realtarget,"base_hard_association"statusbar)
      
$LightweightEvents.addLightweightEventListener(realtarget"nameUpdated"statusbar)
      
$LightweightEvents.addLightweightEventListener(realtarget"hpUpdated"statusbar)
      
statusbar.SetHP(realtarget.curTotalHitPoints,realtarget.maxTotalHitPoints)
      
statusbar.SetName(realtarget.name)
    else
      
println(realtarget)
    .
  .
.
public function 
E_SetTargetCircleFromClienttargetID as ID )
  
where me
    is kindof E_TargetCircle
      me
.E_SetTargetCircle(targetID)
    .
  .
  
//println("Target: " + targetID)
  
.

method E_SetTargetCircletargetID as ID )
//  println( "Update targeting circle." )
if me.E_TargetID <> targetID
  
if me.E_TargetingFX != 0
//    println( "Stopping previous target: " + me.E_TargetingFX )
    
sb as NodeRef of Class GUIControl FindGUIControlByName(0,"game.targetStatusBar")
    if 
sb != None
      DestroyNode
(sb)
    .
    
me.E_StopTargetme.E_TargetingFX )
  .
  
target as NodeRef targetID
  
if target != None
//    println( "Setting new target: " + targetID )
    
me.E_TargetID targetID
    caster 
as Class _Target
    caster
._tgtID targetID
    me
.E_TargetingFX $FXSYSTEM.PlayFxFromSpec4castercaster )
    
statusbar as NodeRef of Class E_targetStatusBar CreateNodeFromPrototype("E_targetStatusBar")
    
statusbar.name "targetStatusBar"
    
statusbar.build true
    realtarget 
as NodeRef of Class E_CommonCharacter
    where target 
      is kindof _PlayerAccount
        realtarget 
target.GetMyCharacter()
      .
      default
        
realtarget target
      
.
    .
    if 
realtarget != None
      AddAssociation
(realtarget,"base_hard_association"statusbar)
      
$LightweightEvents.addLightweightEventListener(realtarget"nameUpdated"statusbar)
      
$LightweightEvents.addLightweightEventListener(realtarget"hpUpdated"statusbar)
      
statusbar.SetHP(realtarget.curTotalHitPoints,realtarget.maxTotalHitPoints)
      
statusbar.SetName(realtarget.name)
    else
      
println(realtarget)
    .
  .
.
.
method E_StopTargetfx as ID )
  
fxgroup as NodeRef of Class _FxGroup $FXSYSTEM._GetFxGroupForHandle(me.E_TargetingFX)
  if 
fxgroup != None
    fxgroup
.StopFxEvent()   
  .
  
me.E_TargetID 0
  me
.E_TargetingFX 0
.

method GetCameraTarget()
 
cam as NodeRef GetActiveCamera()
 
camOffset as Float GetCameraOffset(cam["CameraName"])
 
camOffset += 0.05
    myPlayer 
as NodeRef GetPlayerCharacterNode()
    
  
acct as NodeRef of Class E_playerAccount GetAccountID()
    
ACCController as NodeRef of Class _ACCController
    ro 
as Vector3
    where myPlayer
      is kindof _ACCControllerOwner
       
        ACCController 
myPlayer._getACCController()

        if 
ACCController <> None
          ro 
ACCController._getGameCameraRotationalOffset()
        .
      .
    .

  
start_pos as Vector3 GetCameraPositioncam["CameraName"] )
  
rotation as Vector3 GetNodeRotationcam )
  
  
rotation.-= ro.y
//  weapon_spec as NodeRef of Class FPS_WeaponSpec = me._specRef
    
distanceFactor as Float 20 camOffset
 
  
  intercept 
as Vector3 = (0,0,0)
  
mesh_name as String ""
  
hit_node as NodeRef None
  
  local_distance 
as Float distanceFactor
  local_intercept 
as Vector3 = (0,0,0)
  
local_mesh_name as String ""
  
local_hit_node as NodeRef None
  
  adjusted_rotation 
as Vector3 rotation
  adjusted_rotation
.*= -1
  adjusted_rotation
.MungeHeadingDegreesadjusted_rotation.)
  
adjusted_rotation.*= -1
  direction 
as Vector3 RotateVector( (0,0,-1), adjusted_rotation )
  
  
excluded_nodes as List of NodeRef
  add back SYSTEM
.INFO.PLAYERCHARACTER to excluded_nodes
  
  local_hit_node 
Raycast3Dstart_posdirectionexcluded_nodeslocal_distancelocal_interceptlocal_mesh_name )
  
  
//if nothing was hit or it wasnt a player or wasnt an npc
  
if (local_hit_node == None) or (local_hit_node != None and (not (local_hit_node is kindof E_playerCharacter)) and (not (local_hit_node is kindof E_nonplayerCharacter)))
    
num_rays as Integer 4
    attack_angle 
as Vector3 = (0.030.00.0)
    
rotation_offset as Vector3 = ((attack_angle.2) * -1, (attack_angle.2) * -1, (attack_angle.2) * -1)
    
    
//fire some more rays at small random rotations
    
loop i from 1 to num_rays
      
if rotation_offset.== 0.0
        rotation_offset
.+= (attack_angle.num_rays)
      .
      
      
adjusted_rotation.= (rotation.rotation_offset.x)
      
adjusted_rotation.*= -1
      adjusted_rotation
.= (rotation.rotation_offset.y)
      
adjusted_rotation.MungeHeadingDegreesadjusted_rotation.)
      
adjusted_rotation.*= -1
      
      direction 
RotateVector( (0,0,-1), adjusted_rotation )
      
      
hit_node Raycast3Dstart_posdirectionexcluded_nodesdistanceFactorinterceptmesh_name )
      
      if (
hit_node != None) and ( (hit_node is kindof E_playerCharacter) or (hit_node is kindof E_nonplayerCharacter) )
        return
      .
      
      
rotation_offset.+= attack_angle.num_rays
      rotation_offset
.+= attack_angle.num_rays
      rotation_offset
.+= attack_angle.num_rays
    
.
  .
  
  
//if none of the spread raycasts hit a player or npc then return what the first raycast did
  
distanceFactor local_distance
  intercept 
local_intercept
  mesh_name 
local_mesh_name
  hit_node 
local_hit_node

      
if distanceFactor camOffset
        add back hit_node to excluded_nodes
//        continue
      
.
      if 
hit_node <> None
       
// println("target - " + character.GetMyName())
        
where hit_node
          is kindof E_playerCharacter
              me
.StopDelayedTargetDrop()
            if 
hit_node <> me.E_TargetID
    
//println("Offset = " + camOffset)
              
$E_TargetCircle.E_SetTargetCircle(hit_node)
////              $Debug._drawDebugRay(sourcePosVec, collideIntercept, 0.02, "00FF00", "00FF00", 0.3, false)
              
   
call server E_playerAccountClassMethods:remoteSetClickTargetaccthit_node )
           .
           return
           
// println("target - " + character)
          //  sendchat("Your Character sees "+ character.name,"GAME")
            
          
.
          
is kindof _NonPlayerCharacter
              me
.StopDelayedTargetDrop()
            if 
hit_node <> me.E_TargetID
              $E_TargetCircle
.E_SetTargetCircle(hit_node)
//              $Debug._drawDebugRay(start_pos, intercept, 0.02, "00FF00", "00FF00", 0.3, false)
              
   
call server E_playerAccountClassMethods:remoteSetClickTargetaccthit_node )
            .
            return
//    println("Offset = " + camOffset)
           // println("target - " + character.GetMyName())
         //            sendchat("Your Character sees "+ character.GetMyName(),"GAME")
          
.
          
is kindof HBNode
            
if me.Za_targetDropDelayTimer.timerState == OFF
//    println("Offset = " + camOffset)
              
me.StartDelayedTargetDrop()
            .
            return
//            $Debug._drawDebugRay(sourcePosVec, collideIntercept, 0.02, "00FF00", "00FF00", 0.3, false)

          
.
          default
            if 
me.Za_targetDropDelayTimer.timerState == OFF
              me
.StartDelayedTargetDrop()
            .
           
// me.E_StopTarget( me.E_TargetingFX )
//            $Debug._drawDebugRay(sourcePosVec, collideIntercept, 0.02, "00FF00", "00FF00", 0.3, false)
          
.
        .
      else
        if 
me.Za_targetDropDelayTimer.timerState == OFF
          me
.StartDelayedTargetDrop()
        .
       
// me.E_StopTarget( me.E_TargetingFX )
      
.
//    .
  
 
« Last Edit: Jul 10, 12, 06:02:44 AM by DragonFist »
Logged

Trixer

  • General Accounts
  • *
  • Posts: 26
    • View Profile
Re: [Solved] Raycast3D Usage
« Reply #21 on: Jul 17, 12, 10:32:22 AM »

Really great stuff here guys!

Just wanted to pop in and say thanks, and push this up a bit there were some question regarding raycasting.
Logged
Lead Programmer and Technical Engineer for Harmonex Neuro Science Research Inc.

DragonFist

  • General Accounts
  • *
  • Posts: 140
    • View Profile
Re: [Solved] Raycast3D Usage
« Reply #22 on: Jul 17, 12, 12:44:24 PM »

I've since discovered the per frame event (findable on the wiki) and have moved the firing off of the time in the above code to that handler.  Seems more efficient than keeping a separate timer going.
Logged

PiscoMaN

  • General Accounts
  • *
  • Posts: 1
    • View Profile
Re: [Solved] Raycast3D Usage
« Reply #23 on: Dec 22, 12, 07:39:53 PM »

Only one question, where did you initialize oncreate method?
Logged
Pages: 1 [2]