Core.Object | +--Engine.Actor | +--Engine.ParticleSystem | +--RuneI.BeamSystem | +--RuneI.TreePt
float
BranchLength
DampFactor
GravAccel
vector
GravDir
MaxVelocityAllowed
MaximumVelocityPickup
TreePt
Parent
name
ParentTag
SpringConstant
SwayVelocity
bool
bAffectsParent
bApplyAcceleration
bApplySway
bLeaf
bRestrictVelocity
bSpring
bStiffRotation
void
ApplySwing(TreePt r1, TreePt r2, float DeltaTime)
// r1 = parent, r2 = child
ElasticCollision(Actor a1, Actor a2)
HitWall(vector HitNormal, Actor HitWall)
PostBeginPlay()
PreBeginPlay()
// Private members // --------------------------------------------------------
SetBranchLength(float len)
SetGravDir(vector dir)
// Public interface members // --------------------------------------------------------
Touch(Actor Other)
UnTouch(Actor Other)
WakeSelfAndChildren()
WakeSelfAndParents()
WakeUp()
BeginState()
Tick(float DeltaTime)
00001 //============================================================================= 00002 // TreePt. 00003 //============================================================================= 00004 class TreePt extends BeamSystem; 00005 00006 var() float MaximumVelocityPickup; // Maximum velocity transfer allowed from collision 00007 var() bool bRestrictVelocity; // Restrict TreePt velocity to MaxVelocityAllowed 00008 var() bool bAffectsParent; // If children affect parent velocity 00009 var() float MaxVelocityAllowed; // Creates cone centered at DesiredRotation 00010 var() float GravAccel; // Acceleration magnitude of gravitation 00011 var() float DampFactor; // Dampening Factor [0..1] (1=infinite damp) 00012 var() name ParentTag; // Tag of this TreePt's parent 00013 var() bool bApplyAcceleration; // Apply local gravitation force 00014 var() bool bStiffRotation; // Rotation stays perfectly synced with parent 00015 var() bool bSpring; 00016 var() float SpringConstant; 00017 00018 var() bool bApplySway; // Get rid of these, use controller class to sway 00019 var() vector SwayVelocity; 00020 00021 var(Sounds) sound WhileMoving; 00022 var(Sounds) sound HitAWall; 00023 00024 var TreePt Parent; 00025 var bool bLeaf; // This is last TreePt in chain 00026 var vector GravDir; // Direction of gravitation 00027 var float BranchLength; // Distance to parent TreePt 00028 00029 00030 00031 00032 // Public interface members 00033 // -------------------------------------------------------- 00034 00035 function SetGravDir(vector dir) 00036 { 00037 GravDir = Normal(dir); 00038 } 00039 00040 function SetBranchLength(float len) 00041 { 00042 BranchLength = len; 00043 } 00044 00045 00046 // Private members 00047 // -------------------------------------------------------- 00048 00049 00050 function PreBeginPlay() 00051 { 00052 // Validate user set variables 00053 SetPhysics(PHYS_PROJECTILE); // Don't force this, may want gravity 00054 bLeaf = true; // Nodes are leaves until proven otherwise 00055 Parent = None; 00056 DampFactor = FClamp(DampFactor, -1.0, 1.0); 00057 } 00058 00059 00060 function PostBeginPlay() 00061 { 00062 local TreePt PotentialParent; 00063 00064 if (ParentTag == '') 00065 { // Root 00066 SetPhysics(PHYS_NONE); 00067 } 00068 else 00069 { // Fill in 'Parent' based on 'ParentTag' 00070 foreach AllActors(class'TreePt', PotentialParent, ParentTag) 00071 { 00072 // Notice: If more than one matches ParentTag, the last is used 00073 Parent = PotentialParent; 00074 Parent.bLeaf = false; 00075 00076 // Pre-calc variables 00077 GravDir = Location - PotentialParent.Location; 00078 BranchLength = VSize(GravDir); 00079 Gravdir = Normal(GravDir); 00080 Target = Parent; // endpoint of beamsystem 00081 } 00082 } 00083 } 00084 00085 function ElasticCollision(actor a1, actor a2) 00086 { 00087 local float m1,m2,mt; 00088 local vector v1,v2; 00089 00090 m1 = a1.Mass; 00091 m2 = a2.Mass; 00092 mt = m1+m2; 00093 v1 = a1.Velocity; 00094 v2 = a2.Velocity; 00095 a1.Velocity = (m1*v1 + 2*m2*v2 - m2*v1) / mt; 00096 a2.Velocity = (m2*v2 + 2*m1*v1 - m1*v2 ) / mt; 00097 } 00098 00099 function HitWall(vector HitNormal, actor HitWall) 00100 { 00101 PlaySound(HitAWall, , 1.0); 00102 } 00103 00104 function Touch(actor Other) 00105 { 00106 // Note: 00107 // When objects are internally in order such that this touch gets called 00108 // after the swing calculations, velocity can be transfered continually, 00109 // moving the TreePt out of it's orbit. Maybe Touch/UnTouch are not 00110 // behaving as expected. Perhaps moving this swing logic to the physics 00111 // subsystem would cure this ordering problem. 00112 00113 // Non-blocking velocity transfer 00114 if (!Other.IsA('TreePt')) 00115 { 00116 Velocity += Normal(Other.Velocity) * Min(VSize(Other.Velocity), MaximumVelocityPickup); 00117 Disable('Touch'); 00118 WakeUp(); 00119 } 00120 return; 00121 00122 // Rigid body elastic collision 00123 ElasticCollision(Other, self); 00124 Disable('Touch'); 00125 WakeUp(); 00126 } 00127 00128 function UnTouch(actor Other) 00129 { 00130 Enable('Touch'); 00131 } 00132 00133 00134 // r1 = parent, r2 = child 00135 function ApplySwing(TreePt r1, TreePt r2, float DeltaTime) 00136 { 00137 local vector RopeVector, VelocityLookahead, RopeDir, NewLocation,NewVelocity; 00138 local float velmag; 00139 local rotator rot; 00140 local float stretchAmount; 00141 local vector SpringAccel; 00142 local vector loc1, loc2; 00143 00144 if ((r1 == None)||(r2 == None)) 00145 return; 00146 00147 loc1 = r1.Location; 00148 loc2 = r2.Location; 00149 00150 // Apply Acceleration 00151 if (r2.bApplyAcceleration) 00152 r2.Velocity += r2.GravDir*(r2.GravAccel*DeltaTime); 00153 00154 // Apply sway 00155 if (r2.bApplySway)// && (FRand() < 0.1)) 00156 r2.Velocity += SwayVelocity * (FRand() * DeltaTime); 00157 00158 // Apply velocity on child TreePt 00159 VelocityLookahead = Loc2 + (r2.Velocity * DeltaTime); 00160 RopeDir = Normal(Loc1 - VelocityLookahead); 00161 00162 // Find Next child Location 00163 if (r2.bSpring) 00164 { // Apply spring acceleration 00165 RopeVector = Loc1 - Loc2; 00166 stretchAmount = VSize(RopeVector) - r2.BranchLength; 00167 SpringAccel = Normal(RopeVector) * (r2.SpringConstant * stretchAmount / r2.Mass); 00168 NewLocation = VelocityLookahead + SpringAccel * (DeltaTime * DeltaTime); 00169 } 00170 else 00171 { 00172 RopeVector = RopeDir * r2.BranchLength; 00173 NewLocation = Loc1 - RopeVector; 00174 } 00175 00176 NewVelocity = NewLocation - Loc2; 00177 if (r2.bRestrictVelocity) 00178 { 00179 velmag = VSize(NewVelocity); 00180 if (velmag > r2.MaxVelocityAllowed) 00181 { 00182 NewVelocity = Normal(NewVelocity) * r2.MaxVelocityAllowed; 00183 } 00184 } 00185 r2.Velocity = NewVelocity *(1.0-r2.DampFactor)/ DeltaTime; 00186 00187 // Set child's rotation 00188 if (bStiffRotation) 00189 rot = rotator(-RopeVector); // Predicted location 00190 else 00191 rot = rotator(Loc2-Loc1); // Last location (lagged) 00192 rot.Roll = rot.Yaw; 00193 r2.SetRotation(rot); 00194 00195 //*** This needs to be moved to C side *** 00196 if (r1.Parent == None) // Set root rotation too 00197 r1.SetRotation(rot); 00198 00199 // Apply velocity on parent TreePt 00200 if (r2.bAffectsParent) 00201 { 00202 r1.Velocity = (r1.Velocity + (r2.Velocity * 0.5)) * 0.5; 00203 } 00204 00205 // Play WhileMoving Sound 00206 if (VSize(r2.Velocity) > 1.0) 00207 PlaySound(r2.WhileMoving, , 1.0); 00208 } 00209 00210 00211 function WakeSelfAndParents() 00212 { 00213 if (Parent != None) 00214 { 00215 GotoState('Active'); 00216 Parent.WakeSelfAndParents(); 00217 } 00218 } 00219 00220 function WakeSelfAndChildren() 00221 { 00222 local TreePt point; 00223 00224 // Wake myself if not the root 00225 if (Parent != None) 00226 GotoState('Active'); 00227 foreach AllActors(class'TreePt', point) 00228 { 00229 if (point.Parent == self) 00230 point.WakeSelfAndChildren(); 00231 } 00232 } 00233 00234 function WakeUp() 00235 { 00236 WakeSelfAndParents(); 00237 WakeSelfAndChildren(); 00238 } 00239 00240 state Inactive 00241 { 00242 ignores Tick; 00243 00244 function BeginState() 00245 { 00246 SetPhysics(PHYS_NONE); 00247 } 00248 } 00249 00250 00251 auto state Active 00252 { 00253 function Tick(float DeltaTime) 00254 { 00255 local TreePt point; 00256 00257 if (bLeaf) 00258 { 00259 point = self; 00260 while (point != None) 00261 { 00262 ApplySwing(point.Parent, point, DeltaTime); 00263 point = point.Parent; 00264 } 00265 // 00266 } 00267 00268 if ((!bApplySway) && VSize(Velocity) < 0.1) 00269 { 00270 Velocity = vect(0,0,0); 00271 GotoState('Inactive'); 00272 } 00273 } 00274 00275 function BeginState() 00276 { 00277 if (Parent == None) 00278 { // Root 00279 SetPhysics(PHYS_NONE); 00280 } 00281 else 00282 { 00283 SetPhysics(PHYS_PROJECTILE); 00284 } 00285 } 00286 } 00287 00288 defaultproperties 00289 { 00290 MaximumVelocityPickup=500.000000 00291 bAffectsParent=True 00292 GravAccel=950.000000 00293 DampFactor=0.010000 00294 bApplyAcceleration=True 00295 ParticleCount=12 00296 ParticleTexture(0)=Texture'RuneFX.bark1' 00297 NumConPts=4 00298 BeamThickness=4.000000 00299 bEventSystemTick=False 00300 Physics=PHYS_Projectile 00301 Texture=Texture'Engine.S_TreePoint' 00302 CollisionRadius=20.000000 00303 CollisionHeight=20.000000 00304 bCollideActors=True 00305 bCollideWorld=True 00306 }