demand
When the game displays the 3d scene and its ui. When the player shakes the phone left and right,The UI interface will shift left and right accordingly.When shaking up and down,The 3d scene will shift up and down with it.When the phone stops shaking,If the UI or scene is offset, it will automatically return to the initial default position after a pause.
analysis
First of all, the function of this article deals with horizontal screen games (vertical screen games are almost the same,Everyone expands on their own), suppose we pick up the phone to play games,The phone will have four parts,The left-hand side of the left hand and the right-hand side of the right hand,And above and below the screen content (we ’ll use the left-hand side below,Right-hand side, above, below). The tilt of each part will cause the ui or scene offset effect
We can first use an enumeration to define the tilt of these four parts
public enum egyrotype
{
norotate, //do not rotate
toup, //tilt up below the phone
todown, //tilt down below the phone
toleft, //the left hand side tilts down
toright, //right-hand side tilts down
}
Then we can use Unity's gyroscope interface to input some properties of .gyro,To determine the current tilt of the phone,gyroscope has the following properties:
I use two attributes, enabled and gravity,enabled is used to enable or disable the gyroscope function.And gravity returns a vector3 variable, and the return value corresponding to the specific situation,The print log is displayed on the android phone as follows (landscape game,Records the gravity value of an unspecified angle in a certain situation):
When the phone is placed horizontally on the table with the screen facing up,The return value is:(0.0, 0.0, -1.0)
Tilt up and down:
When tilting up from under the phone,The return value of a certain angle (the rotation angle is less than 90 degrees):(0.0, 0.4, -0.9). If the angle is larger, the screen content will be flipped.
When the phone is tilted downwards,The return value of an angle (the rotation angle is less than 90 degrees):(0.0, -0.5, -0.9), when the rotation angle is 90 degrees:(0.0, -1.0, 0.0), when the rotation angle is between 90 degrees and 180 degrees:( 0.0, -0.8, 0.6), when 180 degrees, the screen is facing downwards:(0.0, 0.0, 1.0), if the angle is a bit larger:(0.0, 0.3, 0.9), until the screen content is flipped over.
we can find out
1. When z<0, y>0:when the value of y becomes larger, it is toup, and when it becomes smaller, it is todown
2. When z<0, y<0:when the value of y becomes larger, it becomes toup, and when it becomes smaller, it becomes todown
3. When z>0, y<0:when the value of y becomes larger, it becomes todown, and when it becomes smaller, it becomes toup
4. When z>0, y>0:when the value of y becomes larger, it is todown, and when it becomes smaller, it is toup
5. When z<0 becomes z>0, it is todown, otherwise it is toup
The first four are summed up,When z<0, the value of y becomes toup when it becomes larger, and todown when it becomes smaller. When z>0, the value of y becomes larger to down, and smaller becomes toup
Tilt left and right:
When the left-hand side of the phone is tilted down,The return value of an angle (the angle is less than 90 degrees):(-0.2, 0.0, -1.0), when the angle is 90 degrees:(-1.0, 0.0, 0.0), when the angle is between 90 degrees and 180 degrees:-0.6, 0.0, 0.8)
When the right-hand side of the phone is tilted down,The return value of an angle (the angle is less than 90 degrees):(0.6, 0.0, -0.8), when the angle is 90 degrees:(1.0, 0.0, 0.0), and when the angle is between 90 degrees and 180 degrees:(0.8, 0.0, 0.5)
Can be concluded
1. When z<0, x<0:Tox is smaller when the value of x is smaller, and toright is larger when the value of x is smaller
2. When z>0 and x<0:when the value of x becomes larger, it becomes toleft, and when it becomes smaller, it becomes toright
3. When z<0, x>0:when the value of x becomes larger, it becomes toright, and when it becomes smaller, it becomes toleft
4. When z>0, x>0:when the value of x becomes smaller, it becomes toright, and when it becomes larger, it becomes toleft
That is, when z<0, the value of x becomes toleft when it becomes smaller, and it becomes toright when it becomes larger. When z>0, the value of x becomes larger toleft, and smaller becomes toright
5. When z<0 becomes z>0, if x<0 then toleft, otherwise toright
6. When z>0 becomes z<0, if x<0 then toright, otherwise toleft
Then we can infer the current state of the phone based on these properties,Then go do what we want to do.
According to demand,Whether it ’s a moving object,Still turning the camera to achieve the effect of offset,Will have a maximum offset value,Offset speed,An interval of time to wait when not turning,These parameters need to be set.
Implementation
First we write a script gyromanager, which is mounted on a gameobject in the scene (can also be processed as a singletonCall the start and update methods elsewhere) to detect the current mobile phone status every frame,And call the registration event of the corresponding state.
using system;
using unityengine;
public enum egyrotype
{
norotate, //do not rotate
toup, //tilt up below the phone
todown, //tilt down below the phone
toleft, //the left hand side tilts down
toright, //right-hand side tilts down
}
public class gyromanager:monobehaviour
{
gyroscope mgyro;//Gyroscope
vector2 mcurrentlandscapegyrovalue, mcurrentportraitgyrovalue;//The current horizontal and vertical gravity value
vector2 mlastlandscapegyrovalue, mlastportraitgyrovalue;//The last horizontal and vertical gravity value
public egyrotype landscapeegyrotype, portraitegyrotype;//Horizontal and vertical state of the phone
float mprecision=0.015f;//precision, if the gravity value is within the precision,Think that there is currently no rotation
public int landscapegyrodifference, portraitgyrodifference;//A simulated speed of rotation,The greater the difference in gravity value,The larger the value
bool misenable;//Whether to enable the gyroscope
private void start ()
{
mgyro=input.gyro;
setgyroenable (true);
}
//Events to be executed in each state
public action landscapetranstodefault;
public action<int>landscapetranstoadd;
public action<int>landscapetranstoreduce;
public action portraittranstodefault;
public action<int>portraittranstoadd;
public action<int>portraittranstoreduce;
public void resetlandscape ()
{
landscapeegyrotype=egyrotype.norotate;
setlandscapevalue ();
mlastlandscapegyrovalue=mcurrentlandscapegyrovalue;
landscapegyrodifference=0;
}
public void resetportrait ()
{
portraitegyrotype=egyrotype.norotate;
setportraitvalue ();
mlastportraitgyrovalue=vector2.zero;
portraitgyrodifference=0;
}
void update ()
{
if (misenable)
{
getegyrotype ();
//According to the parsed mobile phone status,Corresponding event
if (landscapeegyrotype == egyrotype.toleft)
{
landscapetranstoreduce?.invoke (landscapegyrodifference);
}
else if (landscapeegyrotype == egyrotype.toright)
{
landscapetranstoadd?.invoke (landscapegyrodifference);
}
else
{
landscapetranstodefault?.invoke ();
}
if (portraitegyrotype == egyrotype.todown)
{
portraittranstoreduce?.invoke (portraitgyrodifference);
}
else if (portraitegyrotype == egyrotype.toup)
{
portraittranstoadd?.invoke (portraitgyrodifference);
}
else
{
portraittranstodefault?.invoke ();
}
}
}
//Turn the gyroscope on or off
public void setgyroenable (bool isenable)
{
if (misenable!=isenable)
{
misenable=isenable;
resetlandscape ();
resetportrait ();
mgyro.enabled=isenable;
}
}
//Parse the current phone status
public void getegyrotype ()
{
setlandscapevalue ();
//landscape
if (isequals (mcurrentlandscapegyrovalue.x, mlastlandscapegyrovalue.x, true))
{
landscapeegyrotype=egyrotype.norotate;
landscapegyrodifference=0;
}
else
{
landscapegyrodifference=(int) (mathf.abs (mcurrentlandscapegyrovalue.x-mlastlandscapegyrovalue.x) * 60);
if (mcurrentlandscapegyrovalue.y<0&&mlastlandscapegyrovalue.y<0)
{
//When z<0, the value of x becomes smaller toleft, and becomes larger toright
if (mcurrentlandscapegyrovalue.x<mlastlandscapegyrovalue.x)
{
landscapeegyrotype=egyrotype.toleft;
}
else
{
landscapeegyrotype=egyrotype.toright;
}
}
else if (mcurrentlandscapegyrovalue.y>0&&mlastlandscapegyrovalue.y>0)
{
//When z>0, the value of x becomes toleft when it becomes larger, and toright when it becomes smaller.
if (mcurrentlandscapegyrovalue.x<mlastlandscapegyrovalue.x)
{
landscapeegyrotype=egyrotype.toright;
}
else
{
landscapeegyrotype=egyrotype.toleft;
}
}
else
{
if (mcurrentlandscapegyrovalue.y<mlastlandscapegyrovalue.y)
{
//when z<0 becomes z>0, if x<0 then toleft, otherwise toright
if (mcurrentlandscapegyrovalue.x>0)
{
landscapeegyrotype=egyrotype.toleft;
}
else
{
landscapeegyrotype=egyrotype.toright;
}
}
else
{
//when z>0 becomes z<0, if x<0 then toright, otherwise toleft
if (mcurrentlandscapegyrovalue.x<0)
{
landscapeegyrotype=egyrotype.toleft;
}
else
{
landscapeegyrotype=egyrotype.toright;
}
}
}
}
mlastlandscapegyrovalue=mcurrentlandscapegyrovalue;
setportraitvalue ();
//portrait
if (isequals (mcurrentportraitgyrovalue.x, mlastportraitgyrovalue.x, false))
{
portraitegyrotype=egyrotype.norotate;
portraitgyrodifference=0;
}
else
{
portraitgyrodifference=(int) (mathf.abs (mcurrentportraitgyrovalue.x-mlastportraitgyrovalue.x) * 60);
if (mcurrentportraitgyrovalue.y<0&&mlastportraitgyrovalue.y<0)
{
//When z<0, the value of y becomes larger to toup, and becomes smaller to todown
if (mcurrentportraitgyrovalue.x<mlastportraitgyrovalue.x)
{
portraitegyrotype=egyrotype.todown;
}
else
{
portraitegyrotype=egyrotype.toup;
}
}
else if (mcurrentportraitgyrovalue.y>0&&mlastportraitgyrovalue.y>0)
{
//when z>0, the value of y becomes larger to down, and smaller becomes toup
if (mcurrentportraitgyrovalue.x<mlastportraitgyrovalue.x)
{
portraitegyrotype=egyrotype.toup;
}
else
{
portraitegyrotype=egyrotype.todown;
}
}
else
{
//When z<0 becomes z>0, it is todown, otherwise it is toup
if (mcurrentportraitgyrovalue.y<mlastportraitgyrovalue.y)
{
//>0 becomes<0
portraitegyrotype=egyrotype.toup;
}
else
{
portraitegyrotype=egyrotype.todown;
}
}
}
mlastportraitgyrovalue=mcurrentportraitgyrovalue;
}
//Read the gravity value
public void setlandscapevalue ()
{
mcurrentlandscapegyrovalue.x=mgyro.gravity.x;
mcurrentlandscapegyrovalue.y=mgyro.gravity.z;
}
public void setportraitvalue ()
{
mcurrentportraitgyrovalue.x=mgyro.gravity.y;
mcurrentportraitgyrovalue.y=mgyro.gravity.z;
}
//Whether the two times are equal
bool isequals (float a, float b, bool islandscape)
{
if ((islandscape && landscapeegyrotype == egyrotype.norotate) || (! islandscape &&portraitegyrotype == egyrotype.norotate))
{
if (mathf.abs (a-b)<0.025f)
{
return true;
}
}
if (mathf.abs (a-b)<mprecision)
{
return true;
}
return false;
}
}
Then we write a script gyrobase for mounting on components that need to be offset according to the state of the phone.Parameters used to set the offset,And the amount of offset calculated in the corresponding state
using system;
using unityengine;
public class gyrobase
{
public float maxvalue;//Maximum offset value
public float defaultvalue;//initial position
float mcurrentvalue;//Current offset
public float speed;//speed
public float duringtime;//waiting interval
float mcurrentduringtime;//current time interval
public action<float>valuechanged;//offset event
public gyromanager mmanager;
float mbackspeed;//rebound speed (a deceleration process)
float backspeed
{
get
{
if (mbackspeed>mminspeed)
{
mbackspeed=mathf.max (mbackspeed-speed * mdeltatime, mminspeed);
}
return mbackspeed;
}
}
float mminspeed;//Minimum speed
float mdeltatime;//time.deltatime
bool mislandscape;//Detect whether the phone is rotated horizontally or vertically
bool misresetbackproperty=false;
//initial assignment
public void init (float maxvalue, float defaultvalue, float speed, float duringtime, bool islandscape, action<float>action)
{
maxvalue=maxvalue;
defaultvalue=defaultvalue;
speed=speed;
duringtime=duringtime;
mminspeed=speed * 0.2f;
mcurrentvalue=defaultvalue;
mislandscape=islandscape;
if (mislandscape)
{
mmanager.landscapetranstodefault +=transtodefault;
mmanager.landscapetranstoadd +=transtoadd;
mmanager.landscapetranstoreduce +=transtoreduce;
}
else
{
mmanager.portraittranstodefault +=transtodefault;
mmanager.portraittranstoadd +=transtoadd;
mmanager.portraittranstoreduce +=transtoreduce;
}
valuechanged=action;
}
//Event clear
public void clear ()
{
if (mislandscape)
{
mmanager.landscapetranstodefault-= transtodefault;
mmanager.landscapetranstoadd-= transtoadd;
mmanager.landscapetranstoreduce-= transtoreduce;
}
else
{
mmanager.portraittranstodefault-= transtodefault;
mmanager.portraittranstoadd-= transtoadd;
mmanager.portraittranstoreduce-= transtoreduce;
}
}
//Reset rebound parameters
void resetbackproperty ()
{
if (! misresetbackproperty)
{
misresetbackproperty=true;
mbackspeed=speed * 0.8f;
mcurrentduringtime=0;
}
}
//When the phone is not rotating,When the interval time is exceeded, it will decelerate and rebound to the default position.
void transtodefault ()
{
misresetbackproperty=false;
mdeltatime=time.deltatime;
mcurrentduringtime +=mdeltatime;
if (mcurrentduringtime>1)
{
valuetodefault ();
valuechanged?.invoke (mcurrentvalue);
}
}
//offset increase
void transtoadd (int difference)
{
resetbackproperty ();
valueaddspeed (difference);
valuechanged?.invoke (mcurrentvalue);
}
//Offset decreases
void transtoreduce (int difference)
{
resetbackproperty ();
valuereducespeed (difference);
valuechanged?.invoke (mcurrentvalue);
}
void valuetodefault ()
{
if (mcurrentvalue>defaultvalue)
{
mcurrentvalue=mathf.max (mcurrentvalue-backspeed * mdeltatime, defaultvalue);
}
else if (mcurrentvalue<defaultvalue)
{
mcurrentvalue=mathf.min (mcurrentvalue + backspeed * mdeltatime, defaultvalue);
}
}
void valueaddspeed (int difference)
{
if (mcurrentvalue<defaultvalue + maxvalue)
{
mcurrentvalue=mathf.min (mcurrentvalue + speed * mdeltatime * difference, defaultvalue + maxvalue);
}
}
void valuereducespeed (int difference)
{
if (mcurrentvalue>defaultvalue-maxvalue)
{
mcurrentvalue=mathf.max (mcurrentvalue-speed * mdeltatime * difference, defaultvalue-maxvalue);
}
}
}
use
For example, our 3d scene will shift up and down with the phone ’s vertical rotation,We can do this by rotating the x-axis of the camera,We just need to write a simple script and mount it on the camera
public class cameragyro:monobehaviour
{
public gyromanager mmanager;
transform mtransform;
vector3 mcameraangle;
gyrobase mgyrobase;
void start ()
{
mtransform=transform;
mcameraangle=vector3.zero;
mgyrobase=new gyrobase ();
mgyrobase.mmanager=mmanager;
mgyrobase.init (5, 0, 5, 1, false, change);
}
void change (float value)
{
mcameraangle.x=value;
mtransform.localeulerangles=mcameraangle;
}
}
Because not all ui scenes that you project will rotate with the phone flipping horizontally,So it cannot be solved directly by the camera,And need to move the ui part that needs to be offset, so we can write a component and only mount it on the ui part that needs to be offset
public class uigyro:monobehaviour
{
public gyromanager mmanager;
void start ()
{
gyrobase mgyrobase=new gyrobase ();
mgyrobase.mmanager=mmanager;
mgyrobase.init (80, transform.localposition.x, 80, 1, true, change);
}
void change (float value)
{
transform.localposition=new vector3 (value, transform.localposition.y);
}
}
This has roughly achieved the desired effect.
- python - you may need to restart the kernel to use updated packages error
- dart - flutter: the instance member'stars' can't be accessed in an initializer error
- php - coincheck api authentication doesn't work
- php - i would like to introduce the coincheck api so that i can make payments with bitcoin on my ec site
- [php] i want to get account information using coincheck api
- the emulator process for avd pixel_2_api_29 was killed occurred when the android studio emulator was started, so i would like to
- javascript - how to check if an element exists in puppeteer
- sh - 'apt-get' is not recognized as an internal or external command, operable program or batch file
- i want to check the type of a shell script variable
- i want to call a child component method from a parent in vuejs