Skip to content

Instantly share code, notes, and snippets.

@Pendrokar
Last active August 21, 2019 10:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pendrokar/005516cc150f67adda30cc467c03d12d to your computer and use it in GitHub Desktop.
Save Pendrokar/005516cc150f67adda30cc467c03d12d to your computer and use it in GitHub Desktop.
Unigine Touchscreen FPS Flight Controls
#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;
}
@Pendrokar
Copy link
Author

Pendrokar commented Feb 28, 2019

  • Doesn't work well with PlayerActor
  • No tap & drag panning
  • May confuse the turning active touch with the movement one

Demonstration video: https://youtu.be/JL9VpBRJk5A

UNIGINE forum post: https://developer.unigine.com/forum/topic/5390-touchscreen-fps-controls/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment