BizHawk/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawkControllers.cs

217 lines
5.0 KiB
C#
Raw Normal View History

2017-08-29 13:18:28 +00:00
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{
/// <summary>
/// Represents a GB add on
/// </summary>
public interface IPort
{
byte Read(IController c);
ushort ReadAccX(IController c);
ushort ReadAccY(IController c);
2017-08-29 13:18:28 +00:00
ControllerDefinition Definition { get; }
void SyncState(Serializer ser);
int PortNum { get; }
}
2017-11-19 20:16:15 +00:00
[DisplayName("Gameboy Controller")]
2017-08-29 13:18:28 +00:00
public class StandardControls : IPort
{
public StandardControls(int portNum)
{
PortNum = portNum;
Definition = new ControllerDefinition
{
2018-10-08 23:54:12 +00:00
Name = "Gameboy Controller H",
2017-08-29 13:18:28 +00:00
BoolButtons = BaseDefinition
.Select(b => "P" + PortNum + " " + b)
.ToList()
};
}
public int PortNum { get; }
public ControllerDefinition Definition { get; }
public byte Read(IController c)
{
byte result = 0xFF;
2018-01-17 22:17:43 +00:00
if (c.IsPressed(Definition.BoolButtons[0]))
{
result -= 4;
}
if (c.IsPressed(Definition.BoolButtons[1]))
{
result -= 8;
}
if (c.IsPressed(Definition.BoolButtons[2]))
{
result -= 2;
}
if (c.IsPressed(Definition.BoolButtons[3]))
{
result -= 1;
}
if (c.IsPressed(Definition.BoolButtons[4]))
{
result -= 128;
}
if (c.IsPressed(Definition.BoolButtons[5]))
{
result -= 64;
}
if (c.IsPressed(Definition.BoolButtons[6]))
{
result -= 32;
}
if (c.IsPressed(Definition.BoolButtons[7]))
2017-08-29 13:18:28 +00:00
{
2018-01-17 22:17:43 +00:00
result -= 16;
2017-08-29 13:18:28 +00:00
}
return result;
}
public ushort ReadAccX(IController c)
{
return 0;
}
public ushort ReadAccY(IController c)
{
return 0;
}
private static readonly string[] BaseDefinition =
{
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power"
};
public void SyncState(Serializer ser)
{
//nothing
}
}
2018-05-28 17:14:40 +00:00
[DisplayName("Gameboy Controller + Tilt")]
public class StandardTilt : IPort
{
2018-05-28 17:14:40 +00:00
public StandardTilt(int portNum)
{
PortNum = portNum;
Definition = new ControllerDefinition
{
2018-05-28 17:14:40 +00:00
Name = "Gameboy Controller + Tilt",
BoolButtons = BaseDefinition
.Select(b => "P" + PortNum + " " + b)
.ToList(),
FloatControls = { "P" + PortNum + " Tilt X", "P" + PortNum + " Tilt Y" },
FloatRanges = { new[] { -45.0f, 0, 45.0f }, new[] { -45.0f, 0, 45.0f } }
};
}
public int PortNum { get; }
2018-05-28 17:14:40 +00:00
public float theta, phi, theta_prev, phi_prev;
public ControllerDefinition Definition { get; }
public byte Read(IController c)
{
byte result = 0xFF;
if (c.IsPressed(Definition.BoolButtons[0]))
{
result -= 4;
}
if (c.IsPressed(Definition.BoolButtons[1]))
{
result -= 8;
}
if (c.IsPressed(Definition.BoolButtons[2]))
{
result -= 2;
}
if (c.IsPressed(Definition.BoolButtons[3]))
{
result -= 1;
}
if (c.IsPressed(Definition.BoolButtons[4]))
{
result -= 128;
}
if (c.IsPressed(Definition.BoolButtons[5]))
{
result -= 64;
}
if (c.IsPressed(Definition.BoolButtons[6]))
{
result -= 32;
}
if (c.IsPressed(Definition.BoolButtons[7]))
{
result -= 16;
}
return result;
}
// acc x is the result of rotating around body y AFTER rotating around body x
// therefore this control scheme gives decreasing sensitivity in X as Y rotation inscreases
public ushort ReadAccX(IController c)
{
2018-05-28 17:14:40 +00:00
theta_prev = theta;
phi_prev = phi;
theta = (float)(c.GetFloat(Definition.FloatControls[1]) * Math.PI / 180.0);
phi = (float)(c.GetFloat(Definition.FloatControls[0]) * Math.PI / 180.0);
float temp = (float)(Math.Cos(theta) * Math.Sin(phi));
2018-05-28 17:14:40 +00:00
// here we add in rates of change parameters.
// a typical rate of change for a fast rotation is guessed at 0.5 rad / frame
// since rotations about X have less of a moment arm compared to by, we take 1/5 of the effect as a baseline
float temp2 = (float)((phi - phi_prev) / 0.5 * 25);
return (ushort)(0x81D0 - Math.Floor(temp * 125) - temp2);
}
// acc y is just the sine of the angle
2018-05-28 17:14:40 +00:00
// we assume that ReadAccX is called first, which updates the the states
public ushort ReadAccY(IController c)
{
2018-05-28 17:14:40 +00:00
float temp = (float)Math.Sin(theta);
// here we add in rates of change parameters.
// a typical rate of change for a fast rotation is guessed at 0.5 rad / frame
// further it will be assumed that the resulting acceleration is roughly eqvuivalent to gravity
float temp2 = (float)((theta - theta_prev)/0.5 * 125);
return (ushort)(0x81D0 - Math.Floor(temp * 125) + temp2);
}
2017-08-29 13:18:28 +00:00
private static readonly string[] BaseDefinition =
{
2018-01-17 14:41:59 +00:00
"Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power"
2017-08-29 13:18:28 +00:00
};
public void SyncState(Serializer ser)
{
2018-05-28 17:14:40 +00:00
// since we need rate of change of angle, need to savestate them
2019-03-28 03:18:58 +00:00
ser.Sync(nameof(theta), ref theta);
2017-08-29 13:18:28 +00:00
}
}
}