Last active
August 21, 2019 10:37
-
-
Save Pendrokar/005516cc150f67adda30cc467c03d12d to your computer and use it in GitHub Desktop.
Unigine Touchscreen FPS Flight Controls
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <core/unigine.h> | |
// This file is in UnigineScript language. | |
// World script, it takes effect only when the world is loaded. | |
Player player; | |
// -1 = not tracked | |
int moveTouchID = -1; | |
int turnTouchID = -1; | |
//int lastNumTouches = 0; | |
int screenSizeX = 1920; | |
int screenSizeY = 1080; | |
int screenCenterX = 960; | |
int screenCenterY = 540; | |
int boundX = 360; | |
int boundY = 360; | |
int offsetX = 40; | |
int offsetY = 30; | |
int maxVelX = 2.0f; // Left/Right | |
int maxVelY = 2.0f; // Forward/Back | |
int maxRotX = 720.0f; // Turn | |
int maxRotY = 180.0f; // Pitch | |
int moveStartBoundX = 0; | |
int moveStartBoundY = 1080; | |
int movePosX; | |
int movePosY; | |
int moveEndBoundX; | |
int moveEndBoundY; | |
int turnStartBoundX = 1670; | |
int turnStartBoundY = 880; | |
int turnPosX; | |
int turnPosY; | |
int turnEndBoundX; | |
int turnEndBoundY; | |
// Info info; | |
/* | |
*/ | |
class Canvas { | |
Gui gui; // gui | |
WidgetCanvas canvas; // canvas | |
vec4 colors[] = ( | |
vec4(1.0f,0.0f,0.0f,0.3f), | |
vec4(0.0f,1.0f,0.0f,0.3f), | |
vec4(0.0f,0.0f,1.0f,1.0f), | |
vec4(1.0f,1.0f,0.0f,0.3f), | |
vec4(0.0f,1.0f,1.0f,1.0f), | |
vec4(1.0f,0.0f,1.0f,1.0f), | |
vec4(1.0f,1.0f,1.0f,0.5f), // 6 | |
vec4(0.5f,0.0f,0.0f,1.0f), | |
vec4(0.0f,0.5f,0.0f,1.0f), | |
vec4(0.0f,0.0f,0.5f,1.0f), | |
); | |
// constructor/destructor | |
Canvas() { | |
gui = engine.getGui(); | |
canvas = new WidgetCanvas(gui); | |
gui.addChild(canvas,GUI_ALIGN_OVERLAP | GUI_ALIGN_BACKGROUND); | |
} | |
~Canvas() { | |
delete canvas; | |
} | |
// polygons | |
void create_polygon(float x,float y,int num,float radius,vec4 color) { | |
int polygon = canvas.addPolygon(); | |
canvas.setPolygonColor(polygon,color); | |
forloop(int i = 0; num) { | |
float s = sin(PI2 * i / num) * radius + x; | |
float c = cos(PI2 * i / num) * radius + y; | |
canvas.addPolygonPoint(polygon,vec3(s,c,0.0f)); | |
} | |
} | |
// update | |
void update() { | |
canvas.clear(); | |
float radius = screenSizeY / 12.0f; | |
// TEST: Mouse testing | |
int x = engine.app.getMouseX(); | |
int y = engine.app.getMouseY(); | |
if ( | |
moveTouchID != -1 | |
//&& engine.app.getMouseButtonState(APP_BUTTON_LEFT) | |
) | |
{ | |
x = engine.app.getTouchX(moveTouchID); | |
y = engine.app.getTouchY(moveTouchID); | |
create_polygon(x,y,16,radius,colors[1]); | |
} | |
if ( | |
turnTouchID != -1 | |
//&& engine.app.getMouseButtonState(APP_BUTTON_LEFT) | |
) | |
{ | |
x = engine.app.getTouchX(turnTouchID); | |
y = engine.app.getTouchY(turnTouchID); | |
create_polygon(x,y,16,radius,colors[3]); | |
} | |
create_polygon(movePosX, movePosY, 32, boundY / 2,colors[6]); | |
create_polygon(turnPosX, turnPosY, 32, boundY / 2,colors[6]); | |
} | |
// save/restore state | |
void __restore__() { | |
__Canvas__(); | |
} | |
}; | |
Canvas canvas; | |
int init() { | |
screenSizeX = engine.app.getWidth(); | |
screenSizeY = engine.app.getHeight(); | |
screenCenterX = screenSizeX / 2; | |
screenCenterY = screenSizeY / 2; | |
moveStartBoundX = 0; | |
moveStartBoundY = screenSizeY - boundY - offsetY; | |
movePosX = moveStartBoundX + boundX / 2 + offsetX; | |
movePosY = moveStartBoundY + boundY / 2; | |
moveEndBoundX = moveStartBoundX + boundX + offsetX; | |
moveEndBoundY = moveStartBoundY + boundY; | |
turnStartBoundX = screenSizeX - boundX - offsetX; | |
turnStartBoundY = moveStartBoundY; | |
turnPosX = turnStartBoundX + boundX / 2; | |
turnPosY = movePosY; | |
turnEndBoundX = turnStartBoundX + boundX; | |
turnEndBoundY = moveEndBoundY; | |
// Write here code to be called on world initialization: initialize resources for your world scene during the world start. | |
// search the node by the specified name | |
int index = engine.editor.findNode("material_ball"); | |
// FPS Fly | |
player = new PlayerSpectator(); | |
// FPS | |
/* | |
player = new PlayerActor(); | |
maxVelX = 10.0f; // Left/Right | |
maxVelY = 10.0f; // Forward/Back | |
maxRotX = 720.0f; // Turn | |
maxRotY = 180.0f; // Pitch | |
*/ | |
player.setPosition(Vec3(211.913f,-307.466f,49.970f)); | |
player.setDirection(Vec3(0.0f,-1.0f,-0.4f)); | |
engine.game.setPlayer(player); | |
player.setControlled(0); | |
canvas = new Canvas(); | |
// get camera of player | |
//Camera camera = player->getCamera(camera); | |
return 1; | |
} | |
// start of the main loop | |
int update() { | |
// Write here code to be called before updating each render frame: specify all graphics-related functions you want to be called every frame while your application executes. | |
// get the frame duration | |
float ifps = engine.game.getIFps(); | |
// Bottom left drag movement | |
// TEST: with mouse | |
//int touchX = engine.app.getMouseX(); | |
//int touchY = engine.app.getMouseY(); | |
int numTouches = engine.app.getNumTouches(); | |
mat4 transform; | |
// shift | |
/*if ( | |
numTouches < 2 | |
&& moveTouchID != -1 | |
&& turnTouchID != -1 | |
) | |
{ | |
moveTouchID = 0; | |
turnTouchID = 0; | |
}*/ | |
// reset and return on no touches | |
if (numTouches == 0) | |
{ | |
moveTouchID = -1; | |
turnTouchID = -1; | |
canvas.update(); | |
return 1; | |
} | |
else | |
{ | |
transform = player.getTransform(); | |
} | |
float velX = 0.0f; | |
float velY = 0.0f; | |
float rotX = 0.0f; | |
float rotY = 0.0f; | |
forloop (int i = 0; numTouches) { | |
int touchX = engine.app.getTouchX(i); | |
int touchY = engine.app.getTouchY(i); | |
if ( | |
moveTouchID == -1 | |
&& touchX < moveEndBoundX | |
&& touchY > moveStartBoundY | |
// TEST: with mouse | |
//&& engine.app.getMouseButtonState(APP_BUTTON_LEFT) | |
) | |
{ | |
if (turnTouchID != i) | |
{ | |
moveTouchID = i; | |
} | |
} | |
if ( | |
moveTouchID == i | |
// TEST: with mouse | |
//&& engine.app.getMouseButtonState(APP_BUTTON_LEFT) | |
) | |
{ | |
// Restrict bounds, TODO Math Min/Max | |
if (touchX < moveStartBoundX) | |
{ | |
touchX = moveStartBoundX; | |
} | |
if (touchX > moveEndBoundX) | |
{ | |
touchX = moveEndBoundX; | |
} | |
/* | |
if (touchY < moveStartBoundY) | |
{ | |
touchY = moveStartBoundY; | |
} | |
if (touchY > moveEndBoundY) | |
{ | |
touchY = moveEndBoundY; | |
} | |
*/ | |
// Calc velocity relative to pivot | |
velX = maxVelX * (float(touchX - movePosX) / float(movePosX)); | |
velY = maxVelY * (float(touchY - movePosY) / float(boundY)); | |
velX = velX * ifps; | |
velY = velY * ifps; | |
//log.message("touchX (%s)\n", typeinfo(touchX)); | |
//log.message("touchY: %s\n", typeinfo(touchY)); | |
//log.message("movePosX (%s)\n", typeinfo(movePosX)); | |
//log.message("movePosX (%s)\n", typeinfo(movePosX)); | |
//log.message("velX: (%s)\n", typeinfo(velX)); | |
//log.message("velY: (%s)\n", typeinfo(velY)); | |
} | |
else | |
{ | |
//moveTouchID = -1; | |
} | |
if ( | |
turnTouchID == -1 | |
&& touchX > turnStartBoundX | |
&& touchY > turnStartBoundY | |
// TEST: with mouse | |
//&& engine.app.getMouseButtonState(APP_BUTTON_LEFT) | |
) | |
{ | |
if (moveTouchID != i) | |
{ | |
turnTouchID = i; | |
} | |
} | |
if ( | |
turnTouchID == i | |
&& touchX > turnStartBoundX | |
&& touchY > turnStartBoundY | |
// TEST: with mouse | |
//&& engine.app.getMouseButtonState(APP_BUTTON_LEFT) | |
) | |
{ | |
// Restrict bounds, TODO Math Max | |
if (touchX < turnStartBoundX) | |
{ | |
touchX = turnStartBoundX; | |
} | |
if (touchX > turnEndBoundX) | |
{ | |
touchX = turnEndBoundX; | |
} | |
if (touchY < turnStartBoundY) | |
{ | |
touchY = turnStartBoundY; | |
} | |
if (touchY > turnEndBoundY) | |
{ | |
touchY = turnEndBoundY; | |
} | |
// Calc velocity relative to pivot | |
// turn | |
rotX = maxRotX * (float(touchX - turnPosX) / float(turnPosX)); | |
// pitch | |
rotY = maxRotY * (float(touchY - turnPosY) / float(boundY)); | |
rotX = rotX * ifps; | |
rotY = rotY * ifps; | |
//log.message("touchX (%s)\n", typeinfo(touchX)); | |
//log.message("touchY: %s\n", typeinfo(touchY)); | |
//log.message("turnPosX (%s)\n", typeinfo(turnPosX)); | |
//log.message("turnPosX (%s)\n", typeinfo(turnPosX)); | |
//log.message("rotX: (%s)\n", typeinfo(rotX)); | |
//log.message("rotY: (%s)\n", typeinfo(rotY)); | |
} | |
else | |
{ | |
turnTouchID = -1; | |
/*if ( | |
// Drag pan on single touch | |
moveTouchID == -1 | |
&& numTouches == 1 | |
) | |
{ | |
rotX = maxRotX / 2 * (float(touchX - screenCenterX) / float(screenCenterX)); | |
rotY = maxRotY / 2 * (float(touchY - screenCenterY) / float(screenCenterY)); | |
rotX = rotX * ifps; | |
rotY = rotY * ifps; | |
}*/ | |
} | |
} | |
// lastNumTouches = numTouches; | |
if ( | |
velX != 0.0f | |
|| velY != 0.0f | |
|| rotX != 0.0f | |
|| rotY != 0.0f | |
) | |
{ | |
transform = transform * translate(Vec3(velX,0.0f,velY)) * rotateX(-rotY) * rotateY(-rotX); // rotation inverted | |
player.setTransform(transform); | |
} | |
canvas.update(); | |
return 1; | |
} | |
int render() { | |
// The engine calls this function before rendering each render frame: correct behavior after the state of the node has been updated. | |
return 1; | |
} | |
int flush() { | |
// Write here code to be called before updating each physics frame: control physics in your application and put non-rendering calculations. | |
// The engine calls flush() with the fixed rate (60 times per second by default) regardless of the FPS value. | |
// WARNING: do not create, delete or change transformations of nodes here, because rendering is already in progress. | |
return 1; | |
} | |
// end of the main loop | |
int shutdown() { | |
// Write here code to be called on world shutdown: delete resources that were created during world script execution to avoid memory leaks. | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Demonstration video: https://youtu.be/JL9VpBRJk5A
UNIGINE forum post: https://developer.unigine.com/forum/topic/5390-touchscreen-fps-controls/