Crosshair: Use analog stick input properly

- 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.
qteditor^2
Lukas Werling 2016-03-12 19:25:05 +01:00
parent 93dcb1d729
commit b8c8bf825c
3 changed files with 47 additions and 98 deletions

View File

@ -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;

View File

@ -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

View File

@ -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$