mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
670 lines
23 KiB
Haxe
670 lines
23 KiB
Haxe
package src;
|
|
|
|
import net.Net;
|
|
import mis.MisParser;
|
|
import h3d.col.Bounds;
|
|
import h3d.col.Plane;
|
|
import h3d.mat.Material;
|
|
import h3d.prim.Cube;
|
|
import h3d.scene.Mesh;
|
|
import src.Settings;
|
|
import hxd.Key;
|
|
import src.Util;
|
|
import h3d.Quat;
|
|
#if hlsdl
|
|
import sdl.Cursor;
|
|
import sdl.Sdl;
|
|
#end
|
|
#if hldx
|
|
import dx.Cursor;
|
|
import dx.Window;
|
|
#end
|
|
import hxd.Window;
|
|
import hxd.Event;
|
|
import src.MarbleWorld;
|
|
import h3d.scene.Object;
|
|
import src.Marble;
|
|
import h3d.Camera;
|
|
import h3d.Vector;
|
|
import hxsl.Types.Matrix;
|
|
import h3d.scene.Scene;
|
|
import src.Gamepad;
|
|
import src.MarbleGame;
|
|
|
|
enum CameraMode {
|
|
FreeOrbit;
|
|
FixedOrbit;
|
|
}
|
|
|
|
class CameraController extends Object {
|
|
var marble:Marble;
|
|
var level:MarbleWorld;
|
|
|
|
public var Position:Vector;
|
|
public var Direction:Vector;
|
|
public var Up:Vector;
|
|
public var LookAtPoint:Vector;
|
|
public var Mode = CameraMode.FixedOrbit;
|
|
public var CameraSensitivity = 0.6;
|
|
public var CameraPanSensitivity = 0.05;
|
|
public var CameraZoomSensitivity = 0.7;
|
|
public var CameraZoomSpeed = 15.0;
|
|
public var CameraZoomDeceleration = 250.0;
|
|
public var CameraSpeed = 15.0;
|
|
|
|
var camZoomSpeed:Float;
|
|
|
|
public var CameraDistance = 2.5;
|
|
public var CameraMinDistance = 1;
|
|
public var CameraMaxDistance = 25;
|
|
public var CameraPitch:Float;
|
|
public var CameraYaw:Float;
|
|
|
|
public var nextCameraYaw:Float;
|
|
public var nextCameraPitch:Float;
|
|
|
|
public var phi:Float;
|
|
public var theta:Float;
|
|
|
|
var lastCamPos:Vector;
|
|
var lastVertTranslation:Vector;
|
|
|
|
public var oob:Bool = false;
|
|
public var finish:Bool = false;
|
|
public var overview:Bool = false;
|
|
|
|
var spectate:Bool = false;
|
|
var spectateMarbleIndex:Int = -1;
|
|
|
|
var overviewCenter:Vector;
|
|
var overviewWidth:Vector;
|
|
var overviewHeight:Float;
|
|
|
|
var _ignoreCursor:Bool = false;
|
|
|
|
public function new(marble:Marble) {
|
|
super();
|
|
this.marble = marble;
|
|
}
|
|
|
|
public function init(level:MarbleWorld) {
|
|
this.level = level;
|
|
// level.scene.addEventListener(onEvent);
|
|
// Sdl.setRelativeMouseMode(true);
|
|
level.scene.camera.setFovX(Settings.optionsSettings.fovX, Settings.optionsSettings.screenWidth / Settings.optionsSettings.screenHeight);
|
|
if (!Net.isMP)
|
|
lockCursor();
|
|
}
|
|
|
|
public function lockCursor() {
|
|
#if js
|
|
var jsCanvas = @:privateAccess Window.getInstance().canvas;
|
|
jsCanvas.focus();
|
|
var pointercontainer = js.Browser.document.querySelector("#pointercontainer");
|
|
pointercontainer.hidden = true;
|
|
#end
|
|
_ignoreCursor = true;
|
|
if (!Util.isTouchDevice())
|
|
Window.getInstance().lockPointer((x, y) -> orbit(x, y));
|
|
#if hl
|
|
Cursor.show(false);
|
|
#end
|
|
}
|
|
|
|
public function unlockCursor() {
|
|
if (!Util.isTouchDevice())
|
|
Window.getInstance().unlockPointer();
|
|
#if hl
|
|
Cursor.show(true);
|
|
#end
|
|
#if js
|
|
var jsCanvas = @:privateAccess Window.getInstance().canvas;
|
|
@:privateAccess Window.getInstance().lockCallback = null; // Fix cursorlock position shit
|
|
var pointercontainer = js.Browser.document.querySelector("#pointercontainer");
|
|
pointercontainer.hidden = false;
|
|
#end
|
|
}
|
|
|
|
public function enableSpectate() {
|
|
spectate = true;
|
|
if (@:privateAccess this.level.playGui.setSpectateMenu(true)) {
|
|
if (Util.isTouchDevice()) {
|
|
MarbleGame.instance.touchInput.setSpectatorControls(true);
|
|
MarbleGame.instance.touchInput.setSpectatorControlsVisibility(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public function stopSpectate() {
|
|
spectate = false;
|
|
@:privateAccess this.level.playGui.setSpectateMenu(false);
|
|
if (Util.isTouchDevice()) {
|
|
MarbleGame.instance.touchInput.setSpectatorControls(false);
|
|
}
|
|
}
|
|
|
|
public function orbit(mouseX:Float, mouseY:Float, isTouch:Bool = false) {
|
|
if (_ignoreCursor) {
|
|
_ignoreCursor = false;
|
|
return;
|
|
}
|
|
var scaleFactor = 1.0 / Window.getInstance().windowToPixelRatio;
|
|
#if js
|
|
scaleFactor = 1 / js.Browser.window.devicePixelRatio;
|
|
#end
|
|
|
|
var deltaposX = mouseX * scaleFactor;
|
|
var deltaposY = mouseY * (Settings.controlsSettings.invertYAxis ? -1 : 1) * scaleFactor;
|
|
|
|
if (deltaposX != 0 || deltaposY != 0) {
|
|
var absX = Math.abs(deltaposX);
|
|
var absY = Math.abs(deltaposY);
|
|
var len = Math.sqrt(deltaposX * deltaposX + deltaposY * deltaposY);
|
|
var max = Math.max(absX, absY);
|
|
if (max > 0.01) {
|
|
deltaposX *= len / max;
|
|
deltaposY *= len / max;
|
|
}
|
|
}
|
|
if (!Settings.controlsSettings.alwaysFreeLook && !Key.isDown(Settings.controlsSettings.freelook)) {
|
|
deltaposY = 0;
|
|
}
|
|
|
|
var factor = isTouch ? Util.lerp(1 / 25, 1 / 15,
|
|
Settings.controlsSettings.cameraSensitivity) : Util.lerp(1 / 1000, 1 / 200, Settings.controlsSettings.cameraSensitivity);
|
|
|
|
// CameraPitch += deltaposY * factor;
|
|
// CameraYaw += deltaposX * factor;
|
|
|
|
nextCameraPitch += deltaposY * factor;
|
|
nextCameraYaw += deltaposX * factor;
|
|
|
|
// var rotX = deltaposX * 0.001 * Settings.controlsSettings.cameraSensitivity * Math.PI * 2;
|
|
// var rotY = deltaposY * 0.001 * Settings.controlsSettings.cameraSensitivity * Math.PI * 2;
|
|
// CameraYaw -= rotX;
|
|
// CameraPitch -= rotY;
|
|
// // CameraYaw = Math.PI / 2;
|
|
// // CameraPitch = Math.PI / 4;
|
|
|
|
// if (CameraPitch > Math.PI / 2)
|
|
// CameraPitch = Math.PI / 2 - 0.001;
|
|
// if (CameraPitch < -Math.PI / 2)
|
|
// CameraPitch = -Math.PI / 2 + 0.001;
|
|
// if (CameraPitch > Math.PI)
|
|
// CameraPitch = 3.141;
|
|
// if (CameraPitch < 0)
|
|
// CameraPitch = 0.001;
|
|
}
|
|
|
|
public function startOverview() {
|
|
var worldBounds = new Bounds();
|
|
var center = new Vector(0, 0, 0);
|
|
for (itr in level.interiors) {
|
|
var itrBounds = itr.getBounds();
|
|
worldBounds.add(itrBounds);
|
|
center.load(center.add(itrBounds.getCenter().toVector()));
|
|
}
|
|
if (level.interiors.length == 0) {
|
|
worldBounds.xMin = -1;
|
|
worldBounds.xMax = 1;
|
|
worldBounds.yMin = -1;
|
|
worldBounds.yMax = 1;
|
|
worldBounds.zMin = -1;
|
|
worldBounds.zMax = 1;
|
|
} else
|
|
center.scale(1 / level.interiors.length);
|
|
|
|
overviewWidth = new Vector(worldBounds.xMax - worldBounds.xMin, worldBounds.yMax - worldBounds.yMin, worldBounds.zMax - worldBounds.zMin);
|
|
if (level.mission.missionInfo.overviewwidth != null) {
|
|
var parseTest = MisParser.parseVector3(level.mission.missionInfo.overviewwidth);
|
|
if (parseTest != null) {
|
|
overviewWidth = parseTest;
|
|
}
|
|
}
|
|
overviewHeight = level.mission.missionInfo.overviewheight != null ? Std.parseFloat(level.mission.missionInfo.overviewheight) : 0.0;
|
|
overviewCenter = center;
|
|
|
|
overview = true;
|
|
}
|
|
|
|
public function stopOverview() {
|
|
overview = false;
|
|
}
|
|
|
|
function doOverviewCamera(currentTime:Float, dt:Float) {
|
|
var angle = Util.adjustedMod(2 * currentTime * Math.PI / 100.0, 2 * Math.PI);
|
|
var distance = overviewWidth.multiply(2.0 / 3.0);
|
|
var offset = new Vector(Math.sin(angle) * distance.x, Math.cos(angle) * distance.y);
|
|
var position = overviewCenter.add(offset);
|
|
|
|
var top = overviewCenter.z + (overviewWidth.z / 2) + overviewHeight;
|
|
position.z = top;
|
|
|
|
var posDist = Math.sqrt((position.x - overviewCenter.x) * (position.x - overviewCenter.x)
|
|
+ (position.y - overviewCenter.y) * (position.y - overviewCenter.y));
|
|
var upOffset = Math.tan(0.5) * posDist / 2;
|
|
// position.load(position.add(new Vector(0, 0, upOffset)));
|
|
|
|
var camera = level.scene.camera;
|
|
camera.pos.load(position);
|
|
camera.target.load(overviewCenter);
|
|
camera.up.x = 0;
|
|
camera.up.y = 0;
|
|
camera.up.z = 1;
|
|
}
|
|
|
|
function doSpectateCamera(currentTime:Float, dt:Float) {
|
|
var camera = level.scene.camera;
|
|
|
|
var lerpt = Math.pow(0.5, dt / 0.032); // Math.min(1, 1 - Math.pow(0.6, dt / 0.032)); // hxd.Math.min(1, 1 - Math.pow(0.6, dt * 600));
|
|
|
|
var cameraPitchDelta = (Key.isDown(Settings.controlsSettings.camBackward) ? 1 : 0)
|
|
- (Key.isDown(Settings.controlsSettings.camForward) ? 1 : 0)
|
|
+ Gamepad.getAxis(Settings.gamepadSettings.cameraYAxis);
|
|
if (Settings.gamepadSettings.invertYAxis)
|
|
cameraPitchDelta = -cameraPitchDelta;
|
|
nextCameraPitch += 0.75 * 5 * cameraPitchDelta * dt * Settings.gamepadSettings.cameraSensitivity;
|
|
var cameraYawDelta = (Key.isDown(Settings.controlsSettings.camRight) ? 1 : 0) - (Key.isDown(Settings.controlsSettings.camLeft) ? 1 : 0)
|
|
+ Gamepad.getAxis(Settings.gamepadSettings.cameraXAxis);
|
|
if (Settings.gamepadSettings.invertXAxis)
|
|
cameraYawDelta = -cameraYawDelta;
|
|
nextCameraYaw += 0.75 * 5 * cameraYawDelta * dt * Settings.gamepadSettings.cameraSensitivity;
|
|
|
|
var limits = spectateMarbleIndex == -1 ? 0.0001 : Math.PI / 4;
|
|
|
|
nextCameraPitch = Math.max(-Math.PI / 2 + limits, Math.min(Math.PI / 2 - 0.0001, nextCameraPitch));
|
|
|
|
CameraYaw = nextCameraYaw; // Util.lerp(CameraYaw, nextCameraYaw, lerpt);
|
|
CameraPitch = nextCameraPitch; // Util.lerp(CameraPitch, nextCameraPitch, lerpt);
|
|
|
|
CameraPitch = Math.max(-Math.PI / 2 + limits, Math.min(Math.PI / 2 - 0.0001, CameraPitch)); // Util.clamp(CameraPitch, -Math.PI / 12, Math.PI / 2);
|
|
|
|
function getRotQuat(v1:Vector, v2:Vector) {
|
|
function orthogonal(v:Vector) {
|
|
var x = Math.abs(v.x);
|
|
var y = Math.abs(v.y);
|
|
var z = Math.abs(v.z);
|
|
var other = x < y ? (x < z ? new Vector(1, 0, 0) : new Vector(0, 0, 1)) : (y < z ? new Vector(0, 1, 0) : new Vector(0, 0, 1));
|
|
return v.cross(other);
|
|
}
|
|
|
|
var u = v1.normalized();
|
|
var v = v2.normalized();
|
|
if (u.multiply(-1).equals(v)) {
|
|
var q = new Quat();
|
|
var o = orthogonal(u).normalized();
|
|
q.x = o.x;
|
|
q.y = o.y;
|
|
q.z = o.z;
|
|
q.w = 0;
|
|
return q;
|
|
}
|
|
var half = u.add(v).normalized();
|
|
var q = new Quat();
|
|
q.w = u.dot(half);
|
|
var vr = u.cross(half);
|
|
q.x = vr.x;
|
|
q.y = vr.y;
|
|
q.z = vr.z;
|
|
return q;
|
|
}
|
|
var orientationQuat = level.getOrientationQuat(currentTime);
|
|
|
|
if (spectateMarbleIndex == -1) {
|
|
@:privateAccess level.playGui.setSpectateMenuText(0);
|
|
var up = new Vector(0, 0, 1);
|
|
up.transform(orientationQuat.toMatrix());
|
|
var directionVector = new Vector(1, 0, 0);
|
|
|
|
var q1 = new Quat();
|
|
q1.initRotateAxis(0, 1, 0, CameraPitch);
|
|
directionVector.transform(q1.toMatrix());
|
|
q1.initRotateAxis(0, 0, 1, CameraYaw);
|
|
directionVector.transform(q1.toMatrix());
|
|
directionVector.transform(orientationQuat.toMatrix());
|
|
|
|
var dy = Gamepad.getAxis(Settings.gamepadSettings.moveYAxis) * CameraSpeed * dt;
|
|
var dx = -Gamepad.getAxis(Settings.gamepadSettings.moveXAxis) * CameraSpeed * dt;
|
|
|
|
if (Key.isDown(Settings.controlsSettings.forward)) {
|
|
dy += CameraSpeed * dt;
|
|
}
|
|
if (Key.isDown(Settings.controlsSettings.backward)) {
|
|
dy -= CameraSpeed * dt;
|
|
}
|
|
if (Key.isDown(Settings.controlsSettings.left)) {
|
|
dx += CameraSpeed * dt;
|
|
}
|
|
if (Key.isDown(Settings.controlsSettings.right)) {
|
|
dx -= CameraSpeed * dt;
|
|
}
|
|
|
|
if (MarbleGame.instance.touchInput.movementInput.pressed) {
|
|
dx = -MarbleGame.instance.touchInput.movementInput.value.x * CameraSpeed * dt;
|
|
dy = -MarbleGame.instance.touchInput.movementInput.value.y * CameraSpeed * dt;
|
|
}
|
|
|
|
if ((!Util.isTouchDevice() && Key.isDown(Settings.controlsSettings.powerup))
|
|
|| (Util.isTouchDevice() && MarbleGame.instance.touchInput.powerupButton.pressed)
|
|
|| Gamepad.isDown(Settings.gamepadSettings.powerup)) {
|
|
dx *= 2;
|
|
dy *= 2;
|
|
}
|
|
|
|
if (Key.isPressed(Settings.controlsSettings.blast)
|
|
|| (MarbleGame.instance.touchInput.blastbutton.pressed && MarbleGame.instance.touchInput.blastbutton.didPressIt)
|
|
|| Gamepad.isPressed(Settings.gamepadSettings.blast)) {
|
|
var freeMarbleIndex = -1;
|
|
|
|
MarbleGame.instance.touchInput.blastbutton.didPressIt = false;
|
|
|
|
for (i in 0...level.marbles.length) {
|
|
var marble = level.marbles[i];
|
|
@:privateAccess if ((marble.connection != null && !marble.connection.spectator)) {
|
|
freeMarbleIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
spectateMarbleIndex = freeMarbleIndex;
|
|
MarbleGame.instance.touchInput.setSpectatorControlsVisibility(true);
|
|
return;
|
|
}
|
|
|
|
var sideDir = directionVector.cross(up);
|
|
|
|
var moveDir = directionVector.multiply(dy).add(sideDir.multiply(dx));
|
|
camera.pos.load(camera.pos.add(moveDir));
|
|
|
|
camera.up = up;
|
|
camera.target = camera.pos.add(directionVector);
|
|
} else {
|
|
@:privateAccess level.playGui.setSpectateMenuText(1);
|
|
if (Key.isPressed(Settings.controlsSettings.left)
|
|
|| (Util.isTouchDevice()
|
|
&& MarbleGame.instance.touchInput.leftButton.pressed
|
|
&& MarbleGame.instance.touchInput.leftButton.didPressIt)) {
|
|
if (Util.isTouchDevice())
|
|
MarbleGame.instance.touchInput.leftButton.didPressIt = false;
|
|
spectateMarbleIndex = (spectateMarbleIndex - 1 + level.marbles.length) % level.marbles.length;
|
|
@:privateAccess while (level.marbles[spectateMarbleIndex].connection == null
|
|
|| level.marbles[spectateMarbleIndex].connection.spectator) {
|
|
spectateMarbleIndex = (spectateMarbleIndex - 1 + level.marbles.length) % level.marbles.length;
|
|
}
|
|
}
|
|
|
|
if (Key.isPressed(Settings.controlsSettings.right)
|
|
|| (Util.isTouchDevice()
|
|
&& MarbleGame.instance.touchInput.rightButton.pressed
|
|
&& MarbleGame.instance.touchInput.rightButton.didPressIt)) {
|
|
if (Util.isTouchDevice())
|
|
MarbleGame.instance.touchInput.rightButton.didPressIt = false;
|
|
spectateMarbleIndex = (spectateMarbleIndex + 1 + level.marbles.length) % level.marbles.length;
|
|
@:privateAccess while (level.marbles[spectateMarbleIndex].connection == null
|
|
|| level.marbles[spectateMarbleIndex].connection.spectator) {
|
|
spectateMarbleIndex = (spectateMarbleIndex + 1 + level.marbles.length) % level.marbles.length;
|
|
}
|
|
}
|
|
|
|
if (Key.isPressed(Settings.controlsSettings.blast)
|
|
|| (MarbleGame.instance.touchInput.blastbutton.pressed && MarbleGame.instance.touchInput.blastbutton.didPressIt)
|
|
|| Gamepad.isPressed(Settings.gamepadSettings.blast)) {
|
|
if (Util.isTouchDevice())
|
|
MarbleGame.instance.touchInput.blastbutton.didPressIt = false;
|
|
spectateMarbleIndex = -1;
|
|
MarbleGame.instance.touchInput.setSpectatorControlsVisibility(false);
|
|
return;
|
|
}
|
|
if (@:privateAccess level.marbles.length <= spectateMarbleIndex) {
|
|
spectateMarbleIndex = -1;
|
|
MarbleGame.instance.touchInput.setSpectatorControlsVisibility(false);
|
|
return;
|
|
}
|
|
|
|
var marblePosition = @:privateAccess level.marbles[spectateMarbleIndex].lastRenderPos;
|
|
var up = new Vector(0, 0, 1);
|
|
up.transform(orientationQuat.toMatrix());
|
|
var directionVector = new Vector(1, 0, 0);
|
|
var cameraVerticalTranslation = new Vector(0, 0, 0.3);
|
|
|
|
var q1 = new Quat();
|
|
q1.initRotateAxis(0, 1, 0, CameraPitch);
|
|
directionVector.transform(q1.toMatrix());
|
|
cameraVerticalTranslation.transform(q1.toMatrix());
|
|
q1.initRotateAxis(0, 0, 1, CameraYaw);
|
|
directionVector.transform(q1.toMatrix());
|
|
cameraVerticalTranslation.transform(q1.toMatrix());
|
|
directionVector.transform(orientationQuat.toMatrix());
|
|
cameraVerticalTranslation.transform(orientationQuat.toMatrix());
|
|
camera.up = up;
|
|
camera.pos = marblePosition.sub(directionVector.multiply(CameraDistance));
|
|
camera.target = marblePosition.add(cameraVerticalTranslation);
|
|
|
|
var closeness = 0.1;
|
|
var rayCastOrigin = marblePosition.add(level.marbles[spectateMarbleIndex].currentUp.multiply(marble._radius));
|
|
|
|
var processedShapes = [];
|
|
for (i in 0...3) {
|
|
var rayCastDirection = camera.pos.sub(rayCastOrigin);
|
|
rayCastDirection = rayCastDirection.add(rayCastDirection.normalized().multiply(2));
|
|
|
|
var rayCastLen = rayCastDirection.length();
|
|
|
|
var results = level.collisionWorld.rayCast(rayCastOrigin, rayCastDirection.normalized(), rayCastLen);
|
|
|
|
var firstHit:octree.IOctreeObject.RayIntersectionData = null;
|
|
var firstHitDistance = 1e8;
|
|
for (result in results) {
|
|
if (!processedShapes.contains(result.object)
|
|
&& (firstHit == null || (rayCastOrigin.distance(result.point) < firstHitDistance))) {
|
|
firstHit = result;
|
|
firstHitDistance = rayCastOrigin.distance(result.point);
|
|
processedShapes.push(result.object);
|
|
}
|
|
}
|
|
|
|
if (firstHit != null) {
|
|
if (firstHitDistance < CameraDistance) {
|
|
// camera.pos = marblePosition.sub(directionVector.multiply(firstHit.distance * 0.7));
|
|
var plane = new Plane(firstHit.normal.x, firstHit.normal.y, firstHit.normal.z, firstHit.point.dot(firstHit.normal));
|
|
var normal = firstHit.normal.multiply(-1);
|
|
// var position = firstHit.point;
|
|
|
|
var projected = plane.project(camera.pos.toPoint());
|
|
var dist = plane.distance(camera.pos.toPoint());
|
|
|
|
if (dist >= closeness)
|
|
break;
|
|
|
|
camera.pos = projected.toVector().add(normal.multiply(-closeness));
|
|
|
|
var forwardVec = marblePosition.sub(camera.pos).normalized();
|
|
var rightVec = camera.up.cross(forwardVec).normalized();
|
|
var upVec = forwardVec.cross(rightVec);
|
|
|
|
camera.target = marblePosition.add(upVec.multiply(0.3));
|
|
camera.up = upVec;
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
this.setPosition(camera.pos.x, camera.pos.y, camera.pos.z);
|
|
}
|
|
|
|
public function update(currentTime:Float, dt:Float) {
|
|
// camera.position.set(marblePosition.x, marblePosition.y, marblePosition.z).sub(directionVector.clone().multiplyScalar(2.5));
|
|
// this.level.scene.camera.target = marblePosition.add(cameraVerticalTranslation);
|
|
// camera.position.add(cameraVerticalTranslation);
|
|
|
|
if (overview) {
|
|
doOverviewCamera(currentTime, dt);
|
|
return;
|
|
}
|
|
|
|
if (spectate) {
|
|
doSpectateCamera(currentTime, dt);
|
|
return;
|
|
}
|
|
|
|
var camera = level.scene.camera;
|
|
|
|
var lerpt = hxd.Math.min(1,
|
|
1 - Math.pow(0.6, dt * 600)); // Math.min(1, 1 - Math.pow(0.6, dt / 0.032)); // hxd.Math.min(1, 1 - Math.pow(0.6, dt * 600));
|
|
|
|
var cameraPitchDelta = (Key.isDown(Settings.controlsSettings.camBackward) ? 1 : 0)
|
|
- (Key.isDown(Settings.controlsSettings.camForward) ? 1 : 0)
|
|
+ Gamepad.getAxis(Settings.gamepadSettings.cameraYAxis);
|
|
if (Settings.gamepadSettings.invertYAxis)
|
|
cameraPitchDelta = -cameraPitchDelta;
|
|
nextCameraPitch += 0.75 * 5 * cameraPitchDelta * dt * Settings.gamepadSettings.cameraSensitivity;
|
|
var cameraYawDelta = (Key.isDown(Settings.controlsSettings.camRight) ? 1 : 0) - (Key.isDown(Settings.controlsSettings.camLeft) ? 1 : 0)
|
|
+ Gamepad.getAxis(Settings.gamepadSettings.cameraXAxis);
|
|
if (Settings.gamepadSettings.invertXAxis)
|
|
cameraYawDelta = -cameraYawDelta;
|
|
nextCameraYaw += 0.75 * 5 * cameraYawDelta * dt * Settings.gamepadSettings.cameraSensitivity;
|
|
|
|
nextCameraPitch = Math.max(-Math.PI / 2 + Math.PI / 4, Math.min(Math.PI / 2 - 0.0001, nextCameraPitch));
|
|
|
|
CameraYaw = nextCameraYaw; // Util.lerp(CameraYaw, nextCameraYaw, lerpt);
|
|
CameraPitch = nextCameraPitch; // Util.lerp(CameraPitch, nextCameraPitch, lerpt);
|
|
|
|
CameraPitch = Math.max(-Math.PI / 2 + Math.PI / 4, Math.min(Math.PI / 2 - 0.0001, CameraPitch)); // Util.clamp(CameraPitch, -Math.PI / 12, Math.PI / 2);
|
|
|
|
function getRotQuat(v1:Vector, v2:Vector) {
|
|
function orthogonal(v:Vector) {
|
|
var x = Math.abs(v.x);
|
|
var y = Math.abs(v.y);
|
|
var z = Math.abs(v.z);
|
|
var other = x < y ? (x < z ? new Vector(1, 0, 0) : new Vector(0, 0, 1)) : (y < z ? new Vector(0, 1, 0) : new Vector(0, 0, 1));
|
|
return v.cross(other);
|
|
}
|
|
|
|
var u = v1.normalized();
|
|
var v = v2.normalized();
|
|
if (u.multiply(-1).equals(v)) {
|
|
var q = new Quat();
|
|
var o = orthogonal(u).normalized();
|
|
q.x = o.x;
|
|
q.y = o.y;
|
|
q.z = o.z;
|
|
q.w = 0;
|
|
return q;
|
|
}
|
|
var half = u.add(v).normalized();
|
|
var q = new Quat();
|
|
q.w = u.dot(half);
|
|
var vr = u.cross(half);
|
|
q.x = vr.x;
|
|
q.y = vr.y;
|
|
q.z = vr.z;
|
|
return q;
|
|
}
|
|
var orientationQuat = level.getOrientationQuat(currentTime);
|
|
|
|
if (this.finish) {
|
|
// Make the camera spin around slowly
|
|
CameraPitch = Util.lerp(this.level.finishPitch, 0.45,
|
|
Util.clamp((this.level.timeState.currentAttemptTime - this.level.finishTime.currentAttemptTime) / 0.3, 0, 1));
|
|
CameraYaw = this.level.finishYaw - (this.level.timeState.currentAttemptTime - this.level.finishTime.currentAttemptTime) / -1.2;
|
|
}
|
|
|
|
if (!this.level.isWatching) {
|
|
if (this.level.isRecording) {
|
|
this.level.replay.recordCameraState(CameraPitch, CameraYaw);
|
|
}
|
|
} else {
|
|
CameraPitch = this.level.replay.currentPlaybackFrame.cameraPitch;
|
|
CameraYaw = this.level.replay.currentPlaybackFrame.cameraYaw;
|
|
}
|
|
|
|
var marblePosition = level.marble.getAbsPos().getPosition();
|
|
var up = new Vector(0, 0, 1);
|
|
up.transform(orientationQuat.toMatrix());
|
|
var directionVector = new Vector(1, 0, 0);
|
|
var cameraVerticalTranslation = new Vector(0, 0, 0.3);
|
|
|
|
var q1 = new Quat();
|
|
q1.initRotateAxis(0, 1, 0, CameraPitch);
|
|
directionVector.transform(q1.toMatrix());
|
|
cameraVerticalTranslation.transform(q1.toMatrix());
|
|
q1.initRotateAxis(0, 0, 1, CameraYaw);
|
|
directionVector.transform(q1.toMatrix());
|
|
cameraVerticalTranslation.transform(q1.toMatrix());
|
|
directionVector.transform(orientationQuat.toMatrix());
|
|
cameraVerticalTranslation.transform(orientationQuat.toMatrix());
|
|
camera.up = up;
|
|
camera.pos = marblePosition.sub(directionVector.multiply(CameraDistance));
|
|
camera.target = marblePosition.add(cameraVerticalTranslation);
|
|
|
|
var closeness = 0.1;
|
|
var rayCastOrigin = marblePosition.add(level.marble.currentUp.multiply(marble._radius));
|
|
|
|
var processedShapes = [];
|
|
for (i in 0...3) {
|
|
var rayCastDirection = camera.pos.sub(rayCastOrigin);
|
|
rayCastDirection = rayCastDirection.add(rayCastDirection.normalized().multiply(2));
|
|
|
|
var rayCastLen = rayCastDirection.length();
|
|
|
|
var results = level.collisionWorld.rayCast(rayCastOrigin, rayCastDirection.normalized(), rayCastLen);
|
|
|
|
var firstHit:octree.IOctreeObject.RayIntersectionData = null;
|
|
var firstHitDistance = 1e8;
|
|
for (result in results) {
|
|
if (!processedShapes.contains(result.object)
|
|
&& (firstHit == null || (rayCastOrigin.distance(result.point) < firstHitDistance))) {
|
|
firstHit = result;
|
|
firstHitDistance = rayCastOrigin.distance(result.point);
|
|
processedShapes.push(result.object);
|
|
}
|
|
}
|
|
|
|
if (firstHit != null) {
|
|
if (firstHitDistance < CameraDistance) {
|
|
// camera.pos = marblePosition.sub(directionVector.multiply(firstHit.distance * 0.7));
|
|
var plane = new Plane(firstHit.normal.x, firstHit.normal.y, firstHit.normal.z, firstHit.point.dot(firstHit.normal));
|
|
var normal = firstHit.normal.multiply(-1);
|
|
// var position = firstHit.point;
|
|
|
|
var projected = plane.project(camera.pos.toPoint());
|
|
var dist = plane.distance(camera.pos.toPoint());
|
|
|
|
if (dist >= closeness)
|
|
break;
|
|
|
|
camera.pos = projected.toVector().add(normal.multiply(-closeness));
|
|
|
|
var forwardVec = marblePosition.sub(camera.pos).normalized();
|
|
var rightVec = camera.up.cross(forwardVec).normalized();
|
|
var upVec = forwardVec.cross(rightVec);
|
|
|
|
camera.target = marblePosition.add(upVec.multiply(0.3));
|
|
camera.up = upVec;
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (oob) {
|
|
camera.pos = lastCamPos;
|
|
camera.target = marblePosition.add(lastVertTranslation);
|
|
}
|
|
|
|
if (!oob) {
|
|
lastCamPos = camera.pos;
|
|
lastVertTranslation = cameraVerticalTranslation;
|
|
}
|
|
|
|
this.setPosition(camera.pos.x, camera.pos.y, camera.pos.z);
|
|
// camera.target = null;
|
|
// camera.target = targetpos.add(cameraVerticalTranslation);
|
|
// this.x = targetpos.x + directionVec.x;
|
|
|
|
// this.y = targetpos.y + directionVec.y;
|
|
// this.z = targetpos.z + directionVec.z;
|
|
// this.level.scene.camera.follow = {pos: this, target: this.marble};
|
|
}
|
|
}
|