dual joy-con support

- add controller icons in the controller selection menu
This commit is contained in:
minenice55 2022-07-24 18:38:00 -04:00
parent 96ac465200
commit a695a4c221
19 changed files with 1495 additions and 1310 deletions

Binary file not shown.

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 8290861ef07e2d74497c02c16ea45608
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 47521c369c3ab7849aeb7e479bad21ea
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c9421977f50da33418300b1de2773909
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,150 @@
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "UI/ControllerShader"
{
Properties
{
_MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
_BodyColor ("Body Colour", Color) = (1,1,1,1)
_BtnColor ("Button Colour", Color) = (1,1,1,1)
_LGripColor ("Left Grip Colour", Color) = (1,1,1,1)
_RGripColor ("Right Grip Colour", Color) = (1,1,1,1)
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
_StencilReadMask ("Stencil Read Mask", Float) = 255
_ColorMask ("Color Mask", Float) = 15
_ClipRect ("Clip Rect", vector) = (-32767, -32767, 32767, 32767)
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Stencil
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
Cull Off
Lighting Off
ZWrite Off
ZTest [unity_GUIZTestMode]
Blend SrcAlpha OneMinusSrcAlpha
ColorMask [_ColorMask]
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#pragma multi_compile __ UNITY_UI_CLIP_RECT
#pragma multi_compile __ UNITY_UI_ALPHACLIP
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
sampler2D _MainTex;
fixed4 _Color;
fixed4 _BodyColor;
fixed4 _BtnColor;
fixed4 _LGripColor;
fixed4 _RGripColor;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
float4 _MainTex_ST;
float4 _MainTex_TexelSize;
struct v2f
{
half2 texcoord : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float3 localPos : TEXCOORD2;
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
};
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
float4 scaleVertex = float4(IN.vertex.xyz, 0); //By setting the last value to 0 it ignores the flipping ( loses relative position if sprite is flipped :( )
float4 wP = mul(unity_ObjectToWorld, scaleVertex); //Get the object to world vertex and store it
OUT.worldPos = wP.xyz; //For use in fragment shader
float4 lP = mul(unity_WorldToObject, scaleVertex); //Get the world to object vertex and store it
OUT.localPos = lP.xyz; //For use in fragment shader
OUT.texcoord = TRANSFORM_TEX(IN.texcoord, _MainTex);
OUT.color = IN.color;
return OUT;
}
fixed4 frag(v2f IN) : SV_Target
{
fixed4 t = tex2D(_MainTex, IN.texcoord)*IN.color;
//Calculate relative position
fixed2 relativeWorld = fixed2(IN.worldPos.x + IN.localPos.x, IN.worldPos.y + IN.localPos.y);
//This becomes the UV for the texture I want to apply to the sprite ( using the sprites width and height )
fixed2 relativePos = fixed2((relativeWorld.x + _MainTex_TexelSize.z), (relativeWorld.y + _MainTex_TexelSize.w));
fixed r = tex2D(_MainTex, IN.texcoord).r;
fixed g = tex2D(_MainTex, IN.texcoord).g;
fixed b = tex2D(_MainTex, IN.texcoord).b;
fixed lg = 0.0;
fixed rg = 0.0;
if (relativePos.x <= 0.5)
{
lg = b;
}
else
{
rg = b;
}
half4 color = _TextureSampleAdd + IN.color;
color.rgb = (r * _BodyColor.rgb) + (g * _BtnColor.rgb) + (lg * _LGripColor.rgb) + (rg * _RGripColor.rgb);
color.a = tex2D(_MainTex, IN.texcoord).a;
#ifdef UNITY_UI_CLIP_RECT
color.a *= UnityGet2DClipping(IN.worldPos.xy, _ClipRect);
#endif
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
}

View file

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: cfe42e963af2b934bb427536d4d29068
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,91 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: UIControllerMaterial
m_Shader: {fileID: 4800000, guid: cfe42e963af2b934bb427536d4d29068, type: 3}
m_ShaderKeywords:
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 2800000, guid: d44d97eed2a444b41be17f9737b43b5f, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
- _BumpScale: 1
- _ColorMask: 15
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _Stencil: 0
- _StencilComp: 8
- _StencilOp: 0
- _StencilReadMask: 255
- _StencilWriteMask: 255
- _UVSec: 0
- _UseUIAlphaClip: 0
- _ZWrite: 1
m_Colors:
- _BodyColor: {r: 0.11764706, g: 0.039215688, b: 0.039215688, a: 1}
- _BtnColor: {r: 0, g: 0.11764706, b: 0.11764706, a: 1}
- _ClipRect: {r: -32767, g: -32767, b: 32767, a: 32767}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _LGripColor: {r: 0.039215688, g: 0.7254902, b: 0.9019608, a: 1}
- _RGripColor: {r: 1, g: 0.23529412, b: 0.15686275, a: 1}
- _Rect: {r: 0, g: 0, b: 1, a: 1}
m_BuildTextureStacks: []

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 55b3a6672a0ec294d8f3edb9c1f94b36
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 KiB

View file

@ -0,0 +1,276 @@
fileFormatVersion: 2
guid: d44d97eed2a444b41be17f9737b43b5f
TextureImporter:
internalIDToNameTable:
- first:
213: 6680111460237765715
second: pcKeyboard
- first:
213: -418123597310507147
second: sonyDualsense
- first:
213: -8353205122300186910
second: sonyDualShock
- first:
213: 997315915213647506
second: nxProcon
- first:
213: 8903944674802394384
second: nxJoyconPair
- first:
213: 9166690998051772148
second: nxJoyconR
- first:
213: 2557230542604182733
second: nxJoyconL
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 2
spriteExtrude: 1
spriteMeshType: 0
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites:
- serializedVersion: 2
name: pcKeyboard
rect:
serializedVersion: 2
x: 55
y: 3305
width: 1190
height: 692
alignment: 0
pivot: {x: 0.5, y: 0.5}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: 35cec77faf584bc50800000000000000
internalID: 6680111460237765715
vertices: []
indices:
edges: []
weights: []
- serializedVersion: 2
name: sonyDualsense
rect:
serializedVersion: 2
x: 1425
y: 3183
width: 1250
height: 869
alignment: 0
pivot: {x: 0.5, y: 0.5}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: 5774916bdc6823af0800000000000000
internalID: -418123597310507147
vertices: []
indices:
edges: []
weights: []
- serializedVersion: 2
name: sonyDualShock
rect:
serializedVersion: 2
x: 2779
y: 3189
width: 1258
height: 797
alignment: 0
pivot: {x: 0.5, y: 0.5}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: 2eee25dc234731c80800000000000000
internalID: -8353205122300186910
vertices: []
indices:
edges: []
weights: []
- serializedVersion: 2
name: nxProcon
rect:
serializedVersion: 2
x: 31
y: 2131
width: 1212
height: 840
alignment: 0
pivot: {x: 0.5, y: 0.5}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: 29e27277a8d27dd00800000000000000
internalID: 997315915213647506
vertices: []
indices:
edges: []
weights: []
- serializedVersion: 2
name: nxJoyconPair
rect:
serializedVersion: 2
x: 1599
y: 2069
width: 852
height: 924
alignment: 0
pivot: {x: 0.5, y: 0.5}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: 015e351b18a219b70800000000000000
internalID: 8903944674802394384
vertices: []
indices:
edges: []
weights: []
- serializedVersion: 2
name: nxJoyconR
rect:
serializedVersion: 2
x: 2923
y: 2590
width: 922
height: 473
alignment: 0
pivot: {x: 0.5, y: 0.5}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: 4f695a045e0a63f70800000000000000
internalID: 9166690998051772148
vertices: []
indices:
edges: []
weights: []
- serializedVersion: 2
name: nxJoyconL
rect:
serializedVersion: 2
x: 2925
y: 2048
width: 924
height: 473
alignment: 0
pivot: {x: 0.5, y: 0.5}
border: {x: 0, y: 0, z: 0, w: 0}
outline: []
physicsShape: []
tessellationDetail: 0
bones: []
spriteID: dc4a3b431ab1d7320800000000000000
internalID: 2557230542604182733
vertices: []
indices:
edges: []
weights: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,8 @@ namespace HeavenStudio.InputSystem
"DualSense"
};
int[] mappings = new int[]
//TODO: see if single joy-con mappings differ from a normal pad (they don't!)
int[] mappings = new[]
{
ButtonMaskUp,
ButtonMaskDown,
@ -33,15 +34,42 @@ namespace HeavenStudio.InputSystem
ButtonMaskR,
ButtonMaskPlus,
};
int[] mappingsSplitLeft = new[]
{
-1,
-1,
-1,
-1,
ButtonMaskLeft,
ButtonMaskDown,
ButtonMaskUp,
ButtonMaskRight,
ButtonMaskSL,
ButtonMaskSR,
ButtonMaskMinus,
};
int[] mappingsSplitRight = new[]
{
-1,
-1,
-1,
-1,
ButtonMaskE,
ButtonMaskN,
ButtonMaskS,
ButtonMaskW,
ButtonMaskSL,
ButtonMaskSR,
ButtonMaskPlus,
};
float stickDeadzone = 0.5f;
int joyshockHandle;
int type;
int splitType;
string joyshockName;
InputDirection hatDirectionCurrent;
InputDirection hatDirectionLast;
//buttons, sticks, triggers
JOY_SHOCK_STATE joyBtStateCurrent, joyBtStateLast;
//gyro and accelerometer
@ -75,8 +103,46 @@ namespace HeavenStudio.InputSystem
public override void UpdateState()
{
//buttons
joyBtStateLast = joyBtStateCurrent;
joyBtStateCurrent = JslGetSimpleState(joyshockHandle);
//stick direction state
//split controllers will need to be rotated to compensate
//left rotates counterclockwise, right rotates clockwise, all by 90 degrees
float xAxis = 0f;
float yAxis = 0f;
if (otherHalf == null)
{
switch (splitType)
{
case SplitLeft:
xAxis = -joyBtStateCurrent.stickLY;
yAxis = joyBtStateCurrent.stickLX;
break;
case SplitRight: //use the right stick instead
xAxis = joyBtStateCurrent.stickRY;
yAxis = -joyBtStateCurrent.stickRX;
break;
case SplitFull:
xAxis = joyBtStateCurrent.stickLX;
yAxis = joyBtStateCurrent.stickLY;
break;
}
}
else
{
xAxis = joyBtStateCurrent.stickLX;
yAxis = joyBtStateCurrent.stickLY;
}
directionStateLast = directionStateCurrent;
directionStateCurrent = 0;
directionStateCurrent |= ((yAxis >= stickDeadzone) ? (1 << ((int) InputDirection.Up)) : 0);
directionStateCurrent |= ((yAxis <= -stickDeadzone) ? (1 << ((int) InputDirection.Down)) : 0);
directionStateCurrent |= ((xAxis >= stickDeadzone) ? (1 << ((int) InputDirection.Right)) : 0);
directionStateCurrent |= ((xAxis <= -stickDeadzone) ? (1 << ((int) InputDirection.Left)) : 0);
//Debug.Log("stick direction: " + directionStateCurrent + "| x axis: " + xAxis + " y axis: " + yAxis);
}
public override string GetDeviceName()
@ -123,17 +189,71 @@ namespace HeavenStudio.InputSystem
public override bool GetButton(int button)
{
return BitwiseUtils.WantCurrent(joyBtStateCurrent.buttons, 1 << mappings[button]);
int bt = 0;
if (otherHalf == null)
{
if (splitType == SplitLeft)
{
bt = mappingsSplitLeft[button];
}
else if (splitType == SplitRight)
{
bt = mappingsSplitRight[button];
}
else
{
bt = mappings[button];
}
return BitwiseUtils.WantCurrent(joyBtStateCurrent.buttons, 1 << bt);
}
bt = mappings[button];
return BitwiseUtils.WantCurrent(joyBtStateCurrent.buttons, 1 << bt) || BitwiseUtils.WantCurrent(otherHalf.joyBtStateCurrent.buttons, 1 << bt);
}
public override bool GetButtonDown(int button)
{
return BitwiseUtils.WantCurrentAndNotLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, 1 << mappings[button]);
int bt = 0;
if (otherHalf == null)
{
if (splitType == SplitLeft)
{
bt = mappingsSplitLeft[button];
}
else if (splitType == SplitRight)
{
bt = mappingsSplitRight[button];
}
else
{
bt = mappings[button];
}
return BitwiseUtils.WantCurrentAndNotLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, 1 << bt);
}
bt = mappings[button];
return BitwiseUtils.WantCurrentAndNotLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, 1 << bt) || BitwiseUtils.WantCurrentAndNotLast(otherHalf.joyBtStateCurrent.buttons, otherHalf.joyBtStateLast.buttons, 1 << bt);
}
public override bool GetButtonUp(int button)
{
return BitwiseUtils.WantNotCurrentAndLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, 1 << mappings[button]);
int bt = 0;
if (otherHalf == null)
{
if (splitType == SplitLeft)
{
bt = mappingsSplitLeft[button];
}
else if (splitType == SplitRight)
{
bt = mappingsSplitRight[button];
}
else
{
bt = mappings[button];
}
return BitwiseUtils.WantNotCurrentAndLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, 1 << bt);
}
bt = mappings[button];
return BitwiseUtils.WantNotCurrentAndLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, 1 << bt) || BitwiseUtils.WantNotCurrentAndLast(otherHalf.joyBtStateCurrent.buttons, otherHalf.joyBtStateLast.buttons, 1 << bt);
}
public override float GetAxis(InputAxis axis)
@ -182,7 +302,7 @@ namespace HeavenStudio.InputSystem
default:
return false;
}
return BitwiseUtils.WantCurrent(joyBtStateCurrent.buttons, 1 << bt);
return GetButton(bt) || BitwiseUtils.WantCurrent(directionStateCurrent, 1 << (int) direction);
}
public override bool GetHatDirectionDown(InputDirection direction)
@ -206,7 +326,7 @@ namespace HeavenStudio.InputSystem
default:
return false;
}
return BitwiseUtils.WantCurrentAndNotLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, 1 << bt);
return GetButtonDown(bt) || BitwiseUtils.WantCurrentAndNotLast(directionStateCurrent, directionStateLast, 1 << (int) direction);
}
public override bool GetHatDirectionUp(InputDirection direction)
@ -230,11 +350,12 @@ namespace HeavenStudio.InputSystem
default:
return false;
}
return BitwiseUtils.WantNotCurrentAndLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, 1 << bt);
return GetButtonUp(bt) || BitwiseUtils.WantNotCurrentAndLast(directionStateCurrent, directionStateLast, 1 << (int) direction);
}
public override void SetPlayer(int? playerNum)
{
//TODO: dualshock 4 and dualsense lightbar colour support
if (playerNum == -1 || playerNum == null)
{
this.playerNum = null;
@ -273,5 +394,37 @@ namespace HeavenStudio.InputSystem
JslSetLightColour(joyshockHandle, 0);
JslSetPlayerNumber(joyshockHandle, 0);
}
public void AssignOtherHalf(InputJoyshock otherHalf, bool force = false)
{
InputFeatures features = otherHalf.GetFeatures();
if (features.HasFlag(InputFeatures.Extra_SplitControllerLeft) || features.HasFlag(InputFeatures.Extra_SplitControllerRight))
{
//two-way link
this.otherHalf = otherHalf;
this.otherHalf.UnAssignOtherHalf(); //juste en cas
this.otherHalf.otherHalf = this;
this.otherHalf.SetPlayer(this.playerNum);
}
else if (force)
{
UnAssignOtherHalf();
}
}
public void UnAssignOtherHalf()
{
if (otherHalf != null)
{
this.otherHalf.otherHalf = null;
this.otherHalf.SetPlayer(-1);
}
otherHalf = null;
}
public InputJoyshock GetOtherHalf()
{
return otherHalf;
}
}
}

View file

@ -142,6 +142,8 @@ namespace HeavenStudio.InputSystem
}
protected int? playerNum;
protected int directionStateCurrent = 0;
protected int directionStateLast = 0;
public abstract void InitializeController();
public abstract void UpdateState(); // Update the state of the controller

View file

@ -198,30 +198,33 @@ namespace HeavenStudio
public static bool GetAnyDirectionDown()
{
return (GetInputController(1).GetButtonDown((int) InputController.ButtonsPad.PadUp)
|| GetInputController(1).GetButtonDown((int) InputController.ButtonsPad.PadDown)
|| GetInputController(1).GetButtonDown((int) InputController.ButtonsPad.PadLeft)
|| GetInputController(1).GetButtonDown((int) InputController.ButtonsPad.PadRight)
InputController c = GetInputController(1);
return (c.GetHatDirectionDown((InputController.InputDirection) UP)
|| c.GetHatDirectionDown((InputController.InputDirection) DOWN)
|| c.GetHatDirectionDown((InputController.InputDirection) LEFT)
|| c.GetHatDirectionDown((InputController.InputDirection) RIGHT)
) && playerHasControl();
}
public static bool GetAnyDirectionUp()
{
return (GetInputController(1).GetButtonUp((int) InputController.ButtonsPad.PadUp)
|| GetInputController(1).GetButtonUp((int) InputController.ButtonsPad.PadDown)
|| GetInputController(1).GetButtonUp((int) InputController.ButtonsPad.PadLeft)
|| GetInputController(1).GetButtonUp((int) InputController.ButtonsPad.PadRight)
InputController c = GetInputController(1);
return (c.GetHatDirectionUp((InputController.InputDirection) UP)
|| c.GetHatDirectionUp((InputController.InputDirection) DOWN)
|| c.GetHatDirectionUp((InputController.InputDirection) LEFT)
|| c.GetHatDirectionUp((InputController.InputDirection) RIGHT)
) && playerHasControl();
}
public static bool GetAnyDirection()
{
return (GetInputController(1).GetButton((int) InputController.ButtonsPad.PadUp)
|| GetInputController(1).GetButton((int) InputController.ButtonsPad.PadDown)
|| GetInputController(1).GetButton((int) InputController.ButtonsPad.PadLeft)
|| GetInputController(1).GetButton((int) InputController.ButtonsPad.PadRight)
InputController c = GetInputController(1);
return (c.GetHatDirection((InputController.InputDirection) UP)
|| c.GetHatDirection((InputController.InputDirection) DOWN)
|| c.GetHatDirection((InputController.InputDirection) LEFT)
|| c.GetHatDirection((InputController.InputDirection) RIGHT)
) && playerHasControl();
}

View file

@ -6,6 +6,7 @@ using UnityEngine.UI;
using TMPro;
using HeavenStudio;
using HeavenStudio.Util;
using HeavenStudio.InputSystem;
using static JSL;
@ -16,28 +17,59 @@ namespace HeavenStudio.Editor
[SerializeField] private TMP_Text numConnectedLabel;
[SerializeField] private TMP_Text currentControllerLabel;
[SerializeField] private TMP_Dropdown controllersDropdown;
[SerializeField] private TMP_Dropdown splitControllersDropdown;
[SerializeField] private GameObject pairSearchItem;
[SerializeField] private GameObject autoSearchLabel;
[SerializeField] private GameObject pairSearchLabel;
[SerializeField] private TMP_Text pairingLabel;
[SerializeField] private List<GameObject> controllerIcons;
[SerializeField] private Material controllerMat;
private bool isAutoSearching = false;
private bool isPairSearching = false;
private bool pairSelectLR = false; //true = left, false = right
private void Start() {
numConnectedLabel.text = "Connected: " + PlayerInput.GetNumControllersConnected();
currentControllerLabel.text = "Current Controller: " + PlayerInput.GetInputController(1).GetDeviceName();
PopulateControllersDropdown();
PopulateSplitControllersDropdown();
ShowControllerIcon(PlayerInput.GetInputController(1));
controllersDropdown.onValueChanged.AddListener(delegate
{
InputController lastController = PlayerInput.GetInputController(1);
InputController newController = PlayerInput.GetInputControllers()[controllersDropdown.value];
lastController.SetPlayer(newController.GetPlayer() != null ? (int) newController.GetPlayer() : -1);
lastController.SetPlayer(-1);
newController.SetPlayer(1);
currentControllerLabel.text = "Current Controller: " + newController.GetDeviceName();
if (typeof(InputJoyshock) == lastController.GetType()) {
InputJoyshock con = (InputJoyshock) lastController;
con.UnAssignOtherHalf();
}
if (typeof(InputJoyshock) == newController.GetType()) {
StartCoroutine(SelectionVibrate((InputJoyshock) newController));
InputJoyshock con = (InputJoyshock) newController;
StartCoroutine(SelectionVibrate(con));
con.UnAssignOtherHalf();
}
currentControllerLabel.text = "Current Controller: " + newController.GetDeviceName();
ShowControllerIcon(newController);
InputController.InputFeatures features = newController.GetFeatures();
if (features.HasFlag(InputController.InputFeatures.Extra_SplitControllerLeft) || features.HasFlag(InputController.InputFeatures.Extra_SplitControllerRight))
{
pairSelectLR = !features.HasFlag(InputController.InputFeatures.Extra_SplitControllerLeft);
pairSearchItem.SetActive(true);
StartPairSearch();
}
else
{
pairSearchItem.SetActive(false);
CancelPairSearch();
}
});
}
@ -46,25 +78,88 @@ namespace HeavenStudio.Editor
var controllers = PlayerInput.GetInputControllers();
foreach (var controller in controllers) {
if (controller.GetLastButtonDown() > 0 || controller.GetLastKeyDown() > 0) {
PlayerInput.GetInputController(1).SetPlayer(controller.GetPlayer() != null ? (int) controller.GetPlayer() : -1);
InputController lastController = PlayerInput.GetInputController(1);
lastController.SetPlayer(-1);
controller.SetPlayer(1);
isAutoSearching = false;
autoSearchLabel.SetActive(false);
controllersDropdown.value = PlayerInput.GetInputControllerId(1);
currentControllerLabel.text = "Current Controller: " + controller.GetDeviceName();
if (typeof(InputJoyshock) == lastController.GetType()) {
((InputJoyshock)lastController).UnAssignOtherHalf();
}
if (typeof(InputJoyshock) == controller.GetType()) {
StartCoroutine(SelectionVibrate((InputJoyshock) controller));
InputJoyshock con = (InputJoyshock) controller;
StartCoroutine(SelectionVibrate(con));
con.UnAssignOtherHalf();
}
currentControllerLabel.text = "Current Controller: " + controller.GetDeviceName();
ShowControllerIcon(controller);
InputController.InputFeatures features = controller.GetFeatures();
if (features.HasFlag(InputController.InputFeatures.Extra_SplitControllerLeft) || features.HasFlag(InputController.InputFeatures.Extra_SplitControllerRight))
{
pairSelectLR = !features.HasFlag(InputController.InputFeatures.Extra_SplitControllerLeft);
pairSearchItem.SetActive(true);
StartPairSearch();
}
else
{
pairSearchItem.SetActive(false);
CancelPairSearch();
}
}
}
}
else if (isPairSearching) {
var controllers = PlayerInput.GetInputControllers();
InputController.InputFeatures lrFlag = pairSelectLR ? InputController.InputFeatures.Extra_SplitControllerLeft : InputController.InputFeatures.Extra_SplitControllerRight;
foreach (var controller in controllers) {
if (controller == PlayerInput.GetInputController(1)) continue;
InputController.InputFeatures features = controller.GetFeatures();
if (!features.HasFlag(lrFlag)) continue;
if (controller.GetLastButtonDown() > 0 || controller.GetLastKeyDown() > 0) {
InputJoyshock con = (InputJoyshock) PlayerInput.GetInputController(1);
con.AssignOtherHalf((InputJoyshock) controller);
isPairSearching = false;
pairSearchLabel.SetActive(false);
currentControllerLabel.text = "Current Controller: " + controller.GetDeviceName();
pairingLabel.text = "Joy-Con (L / R) Selected\nPairing Successful!";
ShowControllerIcon(controller);
StartCoroutine(SelectionVibrate(con));
StartCoroutine(SelectionVibrate((InputJoyshock) controller));
}
}
}
}
public void StartAutoSearch() {
if (!isPairSearching)
{
autoSearchLabel.SetActive(true);
isAutoSearching = true;
}
}
public void StartPairSearch() {
if (!isAutoSearching) {
pairSearchLabel.SetActive(true);
isPairSearching = true;
pairingLabel.text = "Joy-Con (L / R) Selected\nPairing Second Joy-Con...";
}
}
public void CancelPairSearch() {
if (isPairSearching) {
pairSearchLabel.SetActive(false);
isPairSearching = false;
pairingLabel.text = "Joy-Con (L / R) Selected\nPairing was cancelled.";
}
}
public void SearchAndConnectControllers()
{
@ -72,7 +167,6 @@ namespace HeavenStudio.Editor
numConnectedLabel.text = "Connected: " + connected;
currentControllerLabel.text = "Current Controller: " + PlayerInput.GetInputController(1).GetDeviceName();
PopulateControllersDropdown();
PopulateSplitControllersDropdown();
}
public void PopulateControllersDropdown()
@ -89,33 +183,80 @@ namespace HeavenStudio.Editor
controllersDropdown.value = 0;
}
public void PopulateSplitControllersDropdown()
public void ShowControllerIcon(InputController controller)
{
List<TMP_Dropdown.OptionData> dropDownData = new List<TMP_Dropdown.OptionData>();
var vals = PlayerInput.GetInputControllers();
InputController.InputFeatures features;
for (int i = 0; i < vals.Count; i++)
string name = controller.GetDeviceName();
foreach (var icon in controllerIcons)
{
features = vals[i].GetFeatures();
if (features.HasFlag(InputController.InputFeatures.Extra_SplitControllerLeft) || features.HasFlag(InputController.InputFeatures.Extra_SplitControllerRight))
if (icon.name == name)
{
TMP_Dropdown.OptionData optionData = new TMP_Dropdown.OptionData();
optionData.text = vals[i].GetDeviceName();
dropDownData.Add(optionData);
icon.SetActive(true);
}
else
{
icon.SetActive(false);
}
}
splitControllersDropdown.AddOptions(dropDownData);
splitControllersDropdown.value = 0;
//setup material
Color colour;
switch (name)
{
case "Keyboard":
controllerMat.SetColor("_BodyColor", ColorUtility.TryParseHtmlString("#F4F4F4", out colour) ? colour : Color.white);
break;
case "Joy-Con (L)":
case "Joy-Con (R)":
InputJoyshock joy = (InputJoyshock) controller;
controllerMat.SetColor("_BodyColor", BitwiseUtils.IntToRgb(JslGetControllerColour(joy.GetHandle())));
controllerMat.SetColor("_BtnColor", BitwiseUtils.IntToRgb(JslGetControllerButtonColour(joy.GetHandle())));
controllerMat.SetColor("_LGripColor", ColorUtility.TryParseHtmlString("#2F353A", out colour) ? colour : Color.white);
controllerMat.SetColor("_RGripColor", ColorUtility.TryParseHtmlString("#2F353A", out colour) ? colour : Color.white);
break;
case "Joy-Con Pair":
joy = (InputJoyshock) controller;
int joySide = JslGetControllerSplitType(joy.GetHandle());
controllerMat.SetColor("_BodyColor", BitwiseUtils.IntToRgb(joySide == SplitRight ? JslGetControllerButtonColour(joy.GetHandle()) : JslGetControllerButtonColour(joy.GetOtherHalf().GetHandle())));
controllerMat.SetColor("_BtnColor", BitwiseUtils.IntToRgb(joySide == SplitLeft ? JslGetControllerButtonColour(joy.GetHandle()) : JslGetControllerButtonColour(joy.GetOtherHalf().GetHandle())));
controllerMat.SetColor("_LGripColor", BitwiseUtils.IntToRgb(joySide == SplitLeft ? JslGetControllerColour(joy.GetHandle()) : JslGetControllerColour(joy.GetOtherHalf().GetHandle())));
controllerMat.SetColor("_RGripColor", BitwiseUtils.IntToRgb(joySide == SplitRight ? JslGetControllerColour(joy.GetHandle()) : JslGetControllerColour(joy.GetOtherHalf().GetHandle())));
break;
case "Pro Controller":
joy = (InputJoyshock) controller;
controllerMat.SetColor("_BodyColor", BitwiseUtils.IntToRgb(JslGetControllerColour(joy.GetHandle())));
controllerMat.SetColor("_BtnColor", BitwiseUtils.IntToRgb(JslGetControllerButtonColour(joy.GetHandle())));
controllerMat.SetColor("_LGripColor", BitwiseUtils.IntToRgb(JslGetControllerLeftGripColour(joy.GetHandle())));
controllerMat.SetColor("_RGripColor", BitwiseUtils.IntToRgb(JslGetControllerRightGripColour(joy.GetHandle())));
break;
//TODO: dualshock 4 and dualsense lightbar colour support
case "DualShock 4":
controllerMat.SetColor("_BodyColor", ColorUtility.TryParseHtmlString("#E1E2E4", out colour) ? colour : Color.white);
controllerMat.SetColor("_BtnColor", ColorUtility.TryParseHtmlString("#414246", out colour) ? colour : Color.white);
controllerMat.SetColor("_LGripColor", ColorUtility.TryParseHtmlString("#1E6EFA", out colour) ? colour : Color.white);
controllerMat.SetColor("_RGripColor", ColorUtility.TryParseHtmlString("#1E6EFA", out colour) ? colour : Color.white);
break;
case "DualSense":
controllerMat.SetColor("_BodyColor", ColorUtility.TryParseHtmlString("#DEE0EB", out colour) ? colour : Color.white);
controllerMat.SetColor("_BtnColor", ColorUtility.TryParseHtmlString("#272D39", out colour) ? colour : Color.white);
controllerMat.SetColor("_LGripColor", ColorUtility.TryParseHtmlString("#1E6EFA", out colour) ? colour : Color.white);
controllerMat.SetColor("_RGripColor", ColorUtility.TryParseHtmlString("#1E6EFA", out colour) ? colour : Color.white);
break;
default:
controllerMat.SetColor("_BodyColor", new Color(1, 1, 1, 1));
controllerMat.SetColor("_BtnColor", new Color(1, 1, 1, 1));
controllerMat.SetColor("_LGripColor", new Color(1, 1, 1, 1));
controllerMat.SetColor("_RGripColor", new Color(1, 1, 1, 1));
break;
}
}
IEnumerator SelectionVibrate(InputJoyshock controller)
{
JslSetRumbleFrequency(controller.GetHandle(), 0.2f, 0.25f, 80f, 160f);
yield return new WaitForSeconds(0.08f);
JslSetRumbleFrequency(controller.GetHandle(), 0.4f, 0.3f, 80f, 160f);
yield return new WaitForSeconds(0.15f);
JslSetRumbleFrequency(controller.GetHandle(), 0f, 0f, 0f, 0f);
yield return new WaitForSeconds(0.04f);
JslSetRumbleFrequency(controller.GetHandle(), 0.25f, 0f, 640f, 0f);
yield return new WaitForSeconds(0.05f);
JslSetRumbleFrequency(controller.GetHandle(), 0.45f, 0.45f, 160f, 320f);
yield return new WaitForSeconds(0.25f);
JslSetRumbleFrequency(controller.GetHandle(), 0f, 0f, 0f, 0f);
}
}

View file

@ -2,6 +2,8 @@ using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HeavenStudio.Util
{
public static class BitwiseUtils
@ -22,6 +24,7 @@ namespace HeavenStudio.Util
/// <param name="want">The bit(s) to check for.</param>
public static bool WantCurrent(int num, int want)
{
if (want <= 0) return false;
return (num & want) == want;
}
@ -33,6 +36,7 @@ namespace HeavenStudio.Util
/// <param name="want">The bit(s) to check for.</param>
public static bool WantCurrentAndNotLast(int num1, int num2, int want)
{
if (want <= 0) return false;
return ((num1 & want) == want) && ((num2 & want) != want);
}
@ -44,7 +48,16 @@ namespace HeavenStudio.Util
/// <param name="want">The bit(s) to check for.</param>
public static bool WantNotCurrentAndLast(int num1, int num2, int want)
{
if (want <= 0) return false;
return ((num1 & want) != want) && ((num2 & want) == want);
}
public static Color IntToRgb(int value)
{
var red = ( value >> 16 ) & 255;
var green = ( value >> 8 ) & 255;
var blue = ( value >> 0 ) & 255;
return new Color(red/255f, green/255f, blue/255f);
}
}
}