From b8c8bf825ccce21752052c5dfb1ce4ce7f3b449c Mon Sep 17 00:00:00 2001 From: Lukas Werling Date: Sat, 12 Mar 2016 19:25:05 +0100 Subject: [PATCH] Crosshair: Use analog stick input properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Crosshair doesn't work with a dpad anymore. Supporting dpads adds unnecessary complexity, as a gamepad user with dpad will never be competitive with mouse users. - Crosshair isn't bound to item usage anymore, but will always show when the analog stick is outside of a deadzone. Future planned feature: Also use the actual strength to allow distance input in addition to direction. This is used heavily by Knüppeln.c4s. --- .../ClonkControl.ocd/Crosshair.ocd/Script.c | 122 +++++++----------- .../Libraries.ocd/ClonkControl.ocd/Script.c | 3 +- planet/System.ocg/PlayerControls.txt | 20 --- 3 files changed, 47 insertions(+), 98 deletions(-) diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c index b82df0628..515b148dd 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c @@ -5,61 +5,69 @@ Virtual cursor for gamepad controls */ -local crew, angle, dirx, diry, xpos,ypos, analogaim, aiming, menu; +local crew, angle, xpos, ypos, aiming, menu; static const CURSOR_Radius = 100; +// This is supposed to be a constant, but C4Script doesn't allow constant expressions there. +private func CURSOR_Deadzone() { return PLRCON_MaxStrength / 5; } protected func Initialize() { - this["Visibility"] = VIS_None; - dirx = diry = xpos = ypos = 0; + SetVisibility(false); + xpos = ypos = 0; aiming = false; } public func FxMoveTimer() { - var speed = 0; - var dpad_rotatespeed = 35; + var target_angle = Angle(0,0,xpos,ypos)*10; - // dpad mode - if(diry) + if (!Visible() && !InDeadzone()) { - if (diry < 0) speed = -Sin(angle,100,10); - else if (diry > 0) speed = +Sin(angle,100,10); - angle += dpad_rotatespeed*speed/100; - UpdateAnalogpadPos(); + // The player moved the aiming stick while the crosshair wasn't visible: Use angle directly. + angle = target_angle; + SetVisibility(true); } - if(dirx) + else if (!InDeadzone()) { - if (dirx < 0) speed = -Cos(angle,100,10); - else if (dirx > 0) speed = +Cos(angle,100,10); - angle += dpad_rotatespeed*speed/100; - UpdateAnalogpadPos(); - } - // analog pad mode - if(!dirx && !diry) - { - var target_angle = Angle(0,0,xpos,ypos)*10; - var analog_strength = BoundBy(Sqrt(xpos*xpos+ypos*ypos),0,100); - + // Smooth small movements of the stick while the crosshair is visible. var angle_diff = Normalize(target_angle - angle, -1800, 10); - if (angle_diff == 0) angle_diff = 1; - - angle = angle + angle_diff * analog_strength / 100 / 8; + if (Abs(angle_diff) < 450) + angle = angle + angle_diff / 8; + else + angle = target_angle; + } + else if (!aiming) + { + // The player doesn't touch the stick and no item is using the crosshair right now. + SetVisibility(false); } UpdatePosition(); - if(aiming) crew->TriggerHoldingControl(); + crew->TriggerHoldingControl(); } -private func UpdateAnalogpadPos() +private func AnalogStrength() { return BoundBy(Sqrt(xpos*xpos+ypos*ypos), 0, PLRCON_MaxStrength); } +private func InDeadzone() { return AnalogStrength() < CURSOR_Deadzone(); } +private func Visible() { return this.Visibility != VIS_None; } + +// Updates the visibility, returing true if it was changed. +private func SetVisibility(bool visible) { - xpos = Sin(angle/10,100); - ypos = Cos(angle/10,-100); + var newvis, oldvis; + if (visible) + newvis = VIS_Owner; + else + newvis = VIS_None; + oldvis = this.Visibility; + this.Visibility = newvis; + return newvis != oldvis; } public func StartAim(object clonk, bool stealth, object GUImenu) { + aiming = true; + // only reinitialize angle if the crosshair hasn't been there before if(!GetEffect("Move",this)) { @@ -79,22 +87,15 @@ public func StartAim(object clonk, bool stealth, object GUImenu) SetCategory(C4D_StaticBack | C4D_IgnoreFoW); menu = nil; } - - // set starting position for analog pad - UpdateAnalogpadPos(); + + // Aim somewhere useful if the crosshair wasn't visible before. + if (SetVisibility(true)) + angle = 800*(clonk->GetDir()*2-1); crew = clonk; UpdatePosition(); RemoveEffect("Move",this); AddEffect("Move",this,1,1,this); - - if(!stealth) - { - this["Visibility"] = VIS_Owner; - crew->SetComDir(COMD_Stop); - aiming = true; - EnableKeyAimControls(true); - } } private func UpdatePosition() @@ -112,65 +113,34 @@ private func UpdatePosition() private func MirrorCursor() { + return; angle = -Normalize(angle,-1800,10); - UpdateAnalogpadPos(); } public func StopAim() { - RemoveEffect("Move",this); - this["Visibility"] = VIS_None; - dirx = 0; - diry = 0; - EnableKeyAimControls(false); - analogaim = false; aiming = false; } -private func EnableKeyAimControls(bool enable) -{ - SetPlayerControlEnabled(GetOwner(), CON_AimUp, enable); - SetPlayerControlEnabled(GetOwner(), CON_AimDown, enable); - SetPlayerControlEnabled(GetOwner(), CON_AimLeft, enable); - SetPlayerControlEnabled(GetOwner(), CON_AimRight, enable); -} - public func IsAiming() { return aiming; } -public func Aim(int ctrl, object clonk, int strength, int repeat, int release) +public func Aim(int ctrl, object clonk, int strength, int repeat, int status) { // start (stealth) aiming if(!GetEffect("Move",this)) StartAim(clonk,true); // aiming with analog pad - if (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight) + if (status == CONS_Moved && + (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight)) { - dirx = diry = 0; - if(ctrl == CON_AimAxisUp) ypos = -strength; if(ctrl == CON_AimAxisDown) ypos = strength; if(ctrl == CON_AimAxisLeft) xpos = -strength; if(ctrl == CON_AimAxisRight) xpos = strength; - analogaim = true; - return true; - } - // stop - else if (release && !analogaim) - { - if(ctrl == CON_AimUp || ctrl == CON_AimDown) diry = 0; - else if(ctrl == CON_AimLeft || ctrl == CON_AimRight) dirx = 0; - return true; - } - else if(!release /*&& !repeat */ && !analogaim) - { - if(ctrl == CON_AimUp) diry = -1; - else if(ctrl == CON_AimDown) diry = 1; - else if(ctrl == CON_AimLeft) dirx = -1; - else if(ctrl == CON_AimRight) dirx = 1; return true; } return false; diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c index 94f6ae8f1..2014abf5f 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c @@ -239,8 +239,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re CON_Left is still called afterwards. So if the clonk finally starts to aim, the virtual cursor already aims into the direction in which he ran */ - if (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight - || ctrl == CON_AimUp || ctrl == CON_AimDown || ctrl == CON_AimLeft || ctrl == CON_AimRight) + if (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight) { var success = VirtualCursor()->Aim(ctrl,this,strength,repeat,status); // in any case, CON_Aim* is called but it is only successful if the virtual cursor is aiming diff --git a/planet/System.ocg/PlayerControls.txt b/planet/System.ocg/PlayerControls.txt index e29f7f8bd..cea23de6c 100644 --- a/planet/System.ocg/PlayerControls.txt +++ b/planet/System.ocg/PlayerControls.txt @@ -59,26 +59,6 @@ DefaultDisabled=1 CoordinateSpace=Viewport - [ControlDef] - Identifier=AimUp - DefaultDisabled=1 - Hold=1 - - [ControlDef] - Identifier=AimDown - DefaultDisabled=1 - Hold=1 - - [ControlDef] - Identifier=AimLeft - DefaultDisabled=1 - Hold=1 - - [ControlDef] - Identifier=AimRight - DefaultDisabled=1 - Hold=1 - [ControlDef] Identifier=AimAxisUp GUIName=$CON_AimAxisUp$