@@ -393,60 +393,45 @@ if CLIENT then
393393
394394 end
395395
396- local busy_players = WireLib .RegisterPlayerTable ()
397- net .Receive (" wire_fpga_editor_status" , function (len )
398- local ply = net .ReadEntity ()
399- local status = net .ReadBit () ~= 0
400- if not IsValid (ply ) or ply == LocalPlayer () then return end
401-
402- busy_players [ply ] = status or nil
403- end )
404-
405396 local min = math.min
406397 local surface_DrawPoly = surface .DrawPoly
407398 local surface_SetDrawColor = surface .SetDrawColor
408399
409- local nodeColor = Color (100 ,100 ,100 ,255 )
410- local lineColor = Color (70 , 160 , 255 , 255 )
400+ local function tableValue (t , v )
401+ local keys = {}
402+ for k in pairs (t ) do
403+ keys [# keys + 1 ] = k
404+ end
405+ return t [keys [(v - 1 ) % # keys + 1 ]]
406+ end
407+
408+ local nodeColor = Color (100 , 100 , 100 , 255 )
411409
412410 local size = 100
413411 local padding = 100
414412
415413 local node1x , node1y = - padding * 1.5 , padding
416- local node2x , node2y = padding * 1.5 , - padding
417-
418- local anim = {
419- tStart = 0 ,
420- tEnd = 0 ,
421- dir = 1 ,
422- phase = 1 ,
423- speed = 1 ,
424- holdTime = 2.5 ,
425- holdTimer = 0
426- }
427- local reversed = false
414+ local node2x , node2y = padding * 1.5 , - padding
428415
429- local node1 = { offset = 0 , vel = 0 }
430- local node2 = { offset = 0 , vel = 0 }
416+ local springStrength = 40
417+ local damping = 3
418+ local impulsePower = 200
431419
432- local springStrength = 35
433- local damping = 4
434- local impulsePower = 100
420+ local radialSpringStrength = 16
421+ local radialDamping = 6
422+
423+ local curveSegments = 30
424+ local thickness = 10
425+ local half = thickness * 0.5
435426
436427 local function UpdateSpring (node , ft )
437428 local force = - (springStrength * node .offset + damping * node .vel )
438429 node .vel = node .vel + force * ft
439430 node .offset = node .offset + node .vel * ft
440431 end
441432
442- local curveSegments = 20
443- local baseCurve = {}
444- local thickness = 10
445- local half = thickness * 0.5
446-
447- local function BuildBaseCurve (dir )
448-
449- baseCurve = {}
433+ local function BuildBaseCurve (state , dir )
434+ state .baseCurve = {}
450435
451436 local startX , startY , endX , endY
452437 local cx1 , cy1 , cx2 , cy2
@@ -460,7 +445,7 @@ if CLIENT then
460445 cx1 , cy1 = 0 , startY
461446 cx2 , cy2 = 0 , endY
462447
463- reversed = false
448+ state . reversed = false
464449 else
465450 startX = node2x + size * 0.5
466451 startY = node2y
@@ -470,7 +455,7 @@ if CLIENT then
470455 cx1 , cy1 = startX + size * 2 , startY + size * 2
471456 cx2 , cy2 = endX - size * 2 , endY - size * 2
472457
473- reversed = true
458+ state . reversed = true
474459 end
475460
476461 local prevX , prevY
@@ -497,37 +482,70 @@ if CLIENT then
497482 t3 * endY
498483
499484 if prevX then
500- baseCurve [# baseCurve + 1 ] = {
485+ state . baseCurve [# state . baseCurve + 1 ] = {
501486 x1 = prevX ,
502487 y1 = prevY ,
503488 x2 = x ,
504489 y2 = y ,
505- t1 = (i - 1 ) / curveSegments ,
506- t2 = i / curveSegments
490+ t1 = (i - 1 ) / curveSegments ,
491+ t2 = i / curveSegments
507492 }
508493 end
509494
510495 prevX , prevY = x , y
511496 end
512497 end
513498
514- BuildBaseCurve (anim .dir )
499+ local function NewAnimState ()
500+ local state = {
501+ tStart = 0 ,
502+ tEnd = 0 ,
503+ dir = 1 ,
504+ phase = 1 ,
505+ speed = 2.5 ,
506+ holdTime = 1 ,
507+ holdTimer = 0 ,
508+ reversed = false ,
509+ baseCurve = {},
510+ node1 = { offset = 0 , vel = 0 },
511+ node2 = { offset = 0 , vel = 0 },
512+ lastFrame = 0 ,
513+ color = 1 ,
514+ swapSpringPos = 0 ,
515+ swapSpringVel = 0 ,
516+ lastUpdateTime = 0
517+ }
518+ BuildBaseCurve (state , 1 )
519+ return state
520+ end
521+
522+ local busy_players = WireLib .RegisterPlayerTable ()
523+ net .Receive (" wire_fpga_editor_status" , function (len )
524+ local ply = net .ReadEntity ()
525+ local status = net .ReadBit () ~= 0
526+ if not IsValid (ply ) then return end
527+
528+ busy_players [ply ] = status and NewAnimState () or nil
529+ end )
515530
516- local function DrawCachedCurve (tStart , tEnd )
531+ local function DrawCachedCurve (state )
532+ surface_SetDrawColor (tableValue (FPGATypeColor , state .color ))
517533
518- surface_SetDrawColor (lineColor )
534+ local tStart = state .tStart
535+ local tEnd = state .tEnd
536+ local node1 = state .node1
537+ local node2 = state .node2
519538
520539 local startIndex = math.floor (tStart * curveSegments )
521540 local endIndex = math.floor (tEnd * curveSegments )
522541
523542 for i = startIndex + 1 , endIndex do
524- local seg = baseCurve [i ]
543+ local seg = state . baseCurve [i ]
525544 if seg then
526-
527545 local t1 = seg .t1
528546 local t2 = seg .t2
529547
530- if reversed then
548+ if state . reversed then
531549 t1 = 1 - t1
532550 t2 = 1 - t2
533551 end
@@ -560,21 +578,17 @@ if CLIENT then
560578 end
561579 end
562580
563- hook .Add (" PostPlayerDraw" ," wire_fpga_editor_status" ,function (ply )
564-
565- if not busy_players [ply ] then return end
566-
567- local pos = ply :GetPos () + ply :GetUp () * (ply :OBBMaxs ().z + 10 )
568-
569- local angle = (pos - EyePos ()):GetNormalized ():Angle ()
570- angle = Angle (0 , angle .y , 0 )
571- angle :RotateAroundAxis (angle :Up (), - 90 )
572- angle :RotateAroundAxis (angle :Forward (), 90 )
581+ local pi = math.pi
582+ local function ArcPos (t , cx , cy , r , a0 , a1 )
583+ local a = a0 + (a1 - pi - a0 ) * t
584+ return cx + math.cos (a ) * r , cy + math.sin (a ) * r
585+ end
573586
574- local ft = FrameTime ()
587+ local function UpdateAnim (state , ft )
588+ local anim = state
575589
576- UpdateSpring (node1 , ft )
577- UpdateSpring (node2 , ft )
590+ UpdateSpring (anim . node1 , ft )
591+ UpdateSpring (anim . node2 , ft )
578592
579593 if anim .phase == 1 then
580594 anim .tEnd = min (1 , anim .tEnd + anim .speed * ft )
@@ -583,9 +597,9 @@ if CLIENT then
583597 anim .holdTimer = 0
584598
585599 if anim .dir == 1 then
586- node2 .vel = node2 .vel - impulsePower
600+ anim . node2 .vel = anim . node2 .vel - impulsePower
587601 else
588- node1 .vel = node1 .vel - impulsePower
602+ anim . node1 .vel = anim . node1 .vel - impulsePower
589603 end
590604 end
591605
@@ -600,33 +614,100 @@ if CLIENT then
600614 if anim .tStart >= 1 then
601615 anim .tStart = 0
602616 anim .tEnd = 0
603- anim .phase = 1
617+ anim .phase = anim .dir == - 1 and 4 or 1
618+ anim .swapTimer = 0
604619 anim .dir = - anim .dir
620+ anim .color = anim .color + 1
621+ BuildBaseCurve (anim , anim .dir )
605622
606- BuildBaseCurve (anim .dir )
623+ end
624+
625+ elseif anim .phase == 4 then
626+
627+ local force = - (radialSpringStrength * (anim .swapSpringPos - 1 ) + radialDamping * anim .swapSpringVel )
628+ anim .swapSpringVel = anim .swapSpringVel + force * ft
629+ anim .swapSpringPos = anim .swapSpringPos + anim .swapSpringVel * ft
630+
631+ if math.abs (anim .swapSpringPos - 1 ) < 0.01 and math.abs (anim .swapSpringVel ) < 0.02 then
632+ anim .phase = 1
633+ anim .swapSpringPos = 0
607634 end
608635 end
636+ end
637+
638+ local frameNum
639+ local cx = (node1x + node2x ) * 0.5
640+ local cy = (node1y + node2y ) * 0.5
641+
642+ local dx = node1x - cx
643+ local dy = node1y - cy
644+ local r = math.sqrt (dx * dx + dy * dy )
645+
646+ local a1 = math.atan2 (node1y - cy , node1x - cx )
647+ local a2 = math.atan2 (node2y - cy , node2x - cx )
648+
649+ local FPS_LIMIT = 1 / 60
650+
651+ hook .Add (" PostPlayerDraw" , " wire_fpga_editor_status" , function (ply )
652+ local state = busy_players [ply ]
653+ if not state then return end
654+
655+ local lastUpdate = state .lastUpdateTime
656+ local now = RealTime ()
657+ if now - lastUpdate >= FPS_LIMIT then
658+ UpdateAnim (state , now - lastUpdate )
659+ state .lastUpdateTime = now
660+ end
661+
662+ local BoneIndx = ply :LookupBone (" ValveBiped.Bip01_Head1" ) or ply :LookupBone (" ValveBiped.HC_Head_Bone" ) or 0
663+ local BonePos , _BoneAng = ply :GetBonePosition (BoneIndx )
664+
665+ local pos = BonePos + ply :GetUp () * (16 + state .swapSpringVel * 4 )
666+
667+ local angle = (pos - EyePos ()):GetNormalized ():Angle ()
668+ angle = Angle (0 , angle .y , 0 )
669+ angle :RotateAroundAxis (angle :Up (), - 90 )
670+ angle :RotateAroundAxis (angle :Forward (), 90 )
609671
610672 cam .Start3D2D (pos , angle , 0.05 )
611673
674+ local n1x = node1x
675+ local n1y = node1y - size * 0.5 + state .node1 .offset
676+ local n2x = node2x
677+ local n2y = node2y - size * 0.5 + state .node2 .offset
678+
679+ if state .phase == 4 then
680+
681+ local t = state .swapSpringPos
682+
683+ local an1x , an1y = ArcPos (t , cx , cy , r , a1 , a1 )
684+ local an2x , an2y = ArcPos (t , cx , cy , r , a2 , a2 )
685+
686+ n1x = an1x
687+ n1y = an1y - size * 0.5
688+ n2x = an2x
689+ n2y = an2y - size * 0.5
690+ end
691+
692+ if state .phase ~= 4 then
693+ DrawCachedCurve (state )
694+ end
695+
612696 draw .RoundedBox (12 ,
613- node1x - size * 0.5 ,
614- node1y - size * 0.5 + node1 . offset ,
697+ n1x - size * 0.5 ,
698+ n1y ,
615699 size , size ,
616700 nodeColor
617701 )
618702
619703 draw .RoundedBox (12 ,
620- node2x - size * 0.5 ,
621- node2y - size * 0.5 + node2 . offset ,
704+ n2x - size * 0.5 ,
705+ n2y ,
622706 size , size ,
623707 nodeColor
624708 )
625709
626- DrawCachedCurve (anim .tStart , anim .tEnd )
627-
628710 cam .End3D2D ()
629-
630711 end )
631712
632713end
0 commit comments