|
|
@@ -5,8 +5,10 @@
|
|
|
// - Manual control of a bone scene node
|
|
|
// - Implementing 1st and 3rd person cameras, using raycasts to avoid the 3rd person camera clipping into scenery
|
|
|
// - Saving and loading the variables of a script object
|
|
|
+// - Using touch inputs/gyroscope for iOS/Android (implemented through an external file)
|
|
|
|
|
|
#include "Scripts/Utilities/Sample.as"
|
|
|
+#include "Scripts/Utilities/Touch.as"
|
|
|
|
|
|
const int CTRL_FORWARD = 1;
|
|
|
const int CTRL_BACK = 2;
|
|
|
@@ -22,7 +24,7 @@ const float YAW_SENSITIVITY = 0.1f;
|
|
|
const float INAIR_THRESHOLD_TIME = 0.1f;
|
|
|
|
|
|
const float CAMERA_MIN_DIST = 1.0f;
|
|
|
-const float CAMERA_MAX_DIST = 5.0f;
|
|
|
+float CAMERA_MAX_DIST = 5.0f;
|
|
|
|
|
|
Scene@ scene_;
|
|
|
Node@ cameraNode;
|
|
|
@@ -43,6 +45,10 @@ void Start()
|
|
|
// Create the UI content
|
|
|
CreateInstructions();
|
|
|
|
|
|
+ // Activate mobile stuff when appropriate
|
|
|
+ if (GetPlatform() == "Android" || GetPlatform() == "iOS")
|
|
|
+ InitTouchInput();
|
|
|
+
|
|
|
// Subscribe to necessary events
|
|
|
SubscribeToEvents();
|
|
|
}
|
|
|
@@ -198,6 +204,10 @@ void SubscribeToEvents()
|
|
|
|
|
|
// Subscribe to PostUpdate event for updating the camera position after physics simulation
|
|
|
SubscribeToEvent("PostUpdate", "HandlePostUpdate");
|
|
|
+
|
|
|
+ // Sbscribe to mobile touch events
|
|
|
+ if (GetPlatform() == "Android" || GetPlatform() == "iOS")
|
|
|
+ SubscribeToTouchEvents();
|
|
|
}
|
|
|
|
|
|
void HandleUpdate(StringHash eventType, VariantMap& eventData)
|
|
|
@@ -209,44 +219,52 @@ void HandleUpdate(StringHash eventType, VariantMap& eventData)
|
|
|
if (character is null)
|
|
|
return;
|
|
|
|
|
|
- // Get movement controls and assign them to the character logic component. If UI has a focused element, clear controls
|
|
|
- if (ui.focusElement is null)
|
|
|
+ character.controls.Set(CTRL_FORWARD | CTRL_BACK | CTRL_LEFT | CTRL_RIGHT | CTRL_JUMP, false); // clear previous controls
|
|
|
+
|
|
|
+ if (GetPlatform() == "Android" || GetPlatform() == "iOS")
|
|
|
+ updateTouches();
|
|
|
+
|
|
|
+ else // On desktop, get movement controls and assign them to the character logic component
|
|
|
{
|
|
|
- character.controls.Set(CTRL_FORWARD, input.keyDown['W']);
|
|
|
- character.controls.Set(CTRL_BACK, input.keyDown['S']);
|
|
|
- character.controls.Set(CTRL_LEFT, input.keyDown['A']);
|
|
|
- character.controls.Set(CTRL_RIGHT, input.keyDown['D']);
|
|
|
- character.controls.Set(CTRL_JUMP, input.keyDown[KEY_SPACE]);
|
|
|
-
|
|
|
- // Add character yaw & pitch from the mouse motion
|
|
|
- character.controls.yaw += input.mouseMoveX * YAW_SENSITIVITY;
|
|
|
- character.controls.pitch += input.mouseMoveY * YAW_SENSITIVITY;
|
|
|
- // Limit pitch
|
|
|
- character.controls.pitch = Clamp(character.controls.pitch, -80.0f, 80.0f);
|
|
|
-
|
|
|
- // Switch between 1st and 3rd person
|
|
|
- if (input.keyPress['F'])
|
|
|
- firstPerson = !firstPerson;
|
|
|
-
|
|
|
- // Check for loading / saving the scene
|
|
|
- if (input.keyPress[KEY_F5])
|
|
|
- {
|
|
|
- File saveFile(fileSystem.programDir + "Data/Scenes/CharacterDemo.xml", FILE_WRITE);
|
|
|
- scene_.SaveXML(saveFile);
|
|
|
- }
|
|
|
- if (input.keyPress[KEY_F7])
|
|
|
- {
|
|
|
- File loadFile(fileSystem.programDir + "Data/Scenes/CharacterDemo.xml", FILE_READ);
|
|
|
- scene_.LoadXML(loadFile);
|
|
|
- // After loading we have to reacquire the character scene node, as it has been recreated
|
|
|
- // Simply find by name as there's only one of them
|
|
|
- characterNode = scene_.GetChild("Jack", true);
|
|
|
- if (characterNode is null)
|
|
|
- return;
|
|
|
+
|
|
|
+ if (ui.focusElement is null)
|
|
|
+ {
|
|
|
+ character.controls.Set(CTRL_FORWARD, input.keyDown['W']);
|
|
|
+ character.controls.Set(CTRL_BACK, input.keyDown['S']);
|
|
|
+ character.controls.Set(CTRL_LEFT, input.keyDown['A']);
|
|
|
+ character.controls.Set(CTRL_RIGHT, input.keyDown['D']);
|
|
|
+ character.controls.Set(CTRL_JUMP, input.keyDown[KEY_SPACE]);
|
|
|
+
|
|
|
+ // Add character yaw & pitch from the mouse motion
|
|
|
+ character.controls.yaw += input.mouseMoveX * YAW_SENSITIVITY;
|
|
|
+ character.controls.pitch += input.mouseMoveY * YAW_SENSITIVITY;
|
|
|
+ // Limit pitch
|
|
|
+ character.controls.pitch = Clamp(character.controls.pitch, -80.0f, 80.0f);
|
|
|
+
|
|
|
+ // Switch between 1st and 3rd person
|
|
|
+ if (input.keyPress['F'])
|
|
|
+ firstPerson = !firstPerson;
|
|
|
+
|
|
|
+ // Check for loading / saving the scene
|
|
|
+ if (input.keyPress[KEY_F5])
|
|
|
+ {
|
|
|
+ File saveFile(fileSystem.programDir + "Data/Scenes/CharacterDemo.xml", FILE_WRITE);
|
|
|
+ scene_.SaveXML(saveFile);
|
|
|
+ }
|
|
|
+ if (input.keyPress[KEY_F7])
|
|
|
+ {
|
|
|
+ File loadFile(fileSystem.programDir + "Data/Scenes/CharacterDemo.xml", FILE_READ);
|
|
|
+ scene_.LoadXML(loadFile);
|
|
|
+ // After loading we have to reacquire the character scene node, as it has been recreated
|
|
|
+ // Simply find by name as there's only one of them
|
|
|
+ characterNode = scene_.GetChild("Jack", true);
|
|
|
+ if (characterNode is null)
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- else
|
|
|
- character.controls.Set(CTRL_FORWARD | CTRL_BACK | CTRL_LEFT | CTRL_RIGHT | CTRL_JUMP, false);
|
|
|
+// else
|
|
|
+// character.controls.Set(CTRL_FORWARD | CTRL_BACK | CTRL_LEFT | CTRL_RIGHT | CTRL_JUMP, false);
|
|
|
|
|
|
// Set rotation already here so that it's updated every rendering frame instead of every physics frame
|
|
|
characterNode.rotation = Quaternion(character.controls.yaw, Vector3(0.0f, 1.0f, 0.0f));
|
|
|
@@ -284,10 +302,10 @@ void HandlePostUpdate(StringHash eventType, VariantMap& eventData)
|
|
|
else
|
|
|
{
|
|
|
// Third person camera: position behind the character
|
|
|
- Vector3 aimPoint = characterNode.position + rot * Vector3(0.0f, 1.7f, 0.0f);
|
|
|
+ Vector3 aimPoint = characterNode.position + rot * Vector3(0.0f, 1.7f, 0.0f); // You can modify x Vector3 value to translate the fixed character position (indicative range[-2;2])
|
|
|
|
|
|
// Collide camera ray with static physics objects (layer bitmask 2) to ensure we see the character properly
|
|
|
- Vector3 rayDir = dir * Vector3(0.0f, 0.0f, -1.0f);
|
|
|
+ Vector3 rayDir = dir * Vector3(0.0f, 0.0f, -1.0f); // For indoor scenes you can use dir * Vector3(0.0, 0.0, -0.5) to prevent camera from crossing the walls
|
|
|
float rayDistance = CAMERA_MAX_DIST;
|
|
|
PhysicsRaycastResult result = scene_.physicsWorld.RaycastSingle(Ray(aimPoint, rayDir), rayDistance, 2);
|
|
|
if (result.body !is null)
|
|
|
@@ -421,4 +439,4 @@ class Character : ScriptObject
|
|
|
// Reset grounded flag for next frame
|
|
|
onGround = false;
|
|
|
}
|
|
|
-}
|
|
|
+}
|