1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-15 01:24:35 +02:00

#23 multi-aiming

This commit is contained in:
XProger
2017-05-22 00:21:03 +03:00
parent 821f5826c0
commit 296dfc8a0c
3 changed files with 120 additions and 44 deletions

View File

@@ -188,7 +188,12 @@ struct Camera : Controller {
#endif #endif
int lookAt = -1; int lookAt = -1;
if (actTargetEntity > -1) lookAt = actTargetEntity; if (actTargetEntity > -1) lookAt = actTargetEntity;
if (owner->target > -1) lookAt = owner->target; if (owner->arms[0].target > -1 && owner->arms[1].target > -1 && owner->arms[0].target != owner->arms[1].target) {
// two diff targets
} else if (owner->arms[0].target > -1)
lookAt = owner->arms[0].target;
else if (owner->arms[1].target > -1)
lookAt = owner->arms[1].target;
owner->viewTarget = lookAt; owner->viewTarget = lookAt;

View File

@@ -5,7 +5,6 @@
#include "trigger.h" #include "trigger.h"
struct Character : Controller { struct Character : Controller {
int target;
int health; int health;
float tilt; float tilt;
quat rotHead, rotChest; quat rotHead, rotChest;
@@ -38,7 +37,7 @@ struct Character : Controller {
Collision collision; Collision collision;
Character(IGame *game, int entity, int health) : Controller(game, entity), target(-1), health(health), tilt(0.0f), stand(STAND_GROUND), lastInput(0), velocity(0.0f), angleExt(0.0f) { Character(IGame *game, int entity, int health) : Controller(game, entity), health(health), tilt(0.0f), stand(STAND_GROUND), lastInput(0), velocity(0.0f), angleExt(0.0f) {
animation.initOverrides(); animation.initOverrides();
rotHead = rotChest = quat(0, 0, 0, 1); rotHead = rotChest = quat(0, 0, 0, 1);

View File

@@ -203,7 +203,8 @@ struct Lara : Character {
vec3 chestOffset; vec3 chestOffset;
struct Arm { struct Arm {
int target; int tracking; // tracking target (main target)
int target; // target for shooting
float shotTimer; float shotTimer;
quat rot, rotAbs; quat rot, rotAbs;
Weapon::Anim anim; Weapon::Anim anim;
@@ -707,15 +708,16 @@ struct Lara : Character {
void wpnFire() { void wpnFire() {
bool armShot[2] = { false, false }; bool armShot[2] = { false, false };
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (arms[i].anim == Weapon::Anim::FIRE) { Arm &arm = arms[i];
Animation &anim = arms[i].animation; if (arm.anim == Weapon::Anim::FIRE) {
Animation &anim = arm.animation;
//int realFrameIndex = int(arms[i].animation.time * 30.0f / anim->frameRate) % ((anim->frameEnd - anim->frameStart) / anim->frameRate + 1); //int realFrameIndex = int(arms[i].animation.time * 30.0f / anim->frameRate) % ((anim->frameEnd - anim->frameStart) / anim->frameRate + 1);
if (anim.frameIndex != anim.framePrev) { if (anim.frameIndex != anim.framePrev) {
if (anim.frameIndex == 0) { //realFrameIndex < arms[i].animation.framePrev) { if (anim.frameIndex == 0) { //realFrameIndex < arms[i].animation.framePrev) {
if ((input & ACTION) && (target == -1 || (target > -1 && arms[i].target > -1))) { if ((input & ACTION) && (arm.tracking == -1 || arm.target > -1)) {
armShot[i] = true; armShot[i] = true;
} else } else
wpnSetAnim(arms[i], Weapon::IS_ARMED, Weapon::Anim::AIM, 0.0f, -1.0f, target == -1); wpnSetAnim(arm, Weapon::IS_ARMED, Weapon::Anim::AIM, 0.0f, -1.0f, arm.target == -1);
} }
// shotgun reload sound // shotgun reload sound
if (wpnCurrent == Weapon::SHOTGUN) { if (wpnCurrent == Weapon::SHOTGUN) {
@@ -723,9 +725,8 @@ struct Lara : Character {
playSound(TR::SND_SHOTGUN_RELOAD, pos, Sound::Flags::PAN); playSound(TR::SND_SHOTGUN_RELOAD, pos, Sound::Flags::PAN);
} }
} }
} }
arms[i].animation.framePrev = arms[i].animation.frameIndex; arm.animation.framePrev = arm.animation.frameIndex;
if (wpnCurrent == Weapon::SHOTGUN) break; if (wpnCurrent == Weapon::SHOTGUN) break;
} }
@@ -763,8 +764,8 @@ struct Lara : Character {
int room; int room;
vec3 hit = trace(getRoomIndex(), p, t, room, false); vec3 hit = trace(getRoomIndex(), p, t, room, false);
if (target > -1 && checkHit(target, p, hit, hit)) { if (arm->target > -1 && checkHit(arm->target, p, hit, hit)) {
((Character*)level->entities[target].controller)->hit(wpnGetDamage()); ((Character*)level->entities[arm->target].controller)->hit(wpnGetDamage());
hit -= d * 64.0f; hit -= d * 64.0f;
Sprite::add(game, TR::Entity::BLOOD, room, (int)hit.x, (int)hit.y, (int)hit.z, Sprite::FRAME_ANIMATED); Sprite::add(game, TR::Entity::BLOOD, room, (int)hit.x, (int)hit.y, (int)hit.z, Sprite::FRAME_ANIMATED);
} else { } else {
@@ -793,8 +794,9 @@ struct Lara : Character {
if (input & DEATH) { if (input & DEATH) {
arms[0].shotTimer = arms[1].shotTimer = MUZZLE_FLASH_TIME + 1.0f; arms[0].shotTimer = arms[1].shotTimer = MUZZLE_FLASH_TIME + 1.0f;
arms[0].tracking = arms[1].tracking = -1;
arms[0].target = arms[1].target = -1;
animation.overrideMask = 0; animation.overrideMask = 0;
target = -1;
return; return;
} }
@@ -824,12 +826,14 @@ struct Lara : Character {
bool isRifle = wpnCurrent == Weapon::SHOTGUN; bool isRifle = wpnCurrent == Weapon::SHOTGUN;
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (arms[i].target > -1 || ((input & ACTION) && target == -1)) { Arm &arm = arms[i];
if (arms[i].anim == Weapon::Anim::HOLD)
wpnSetAnim(arms[i], wpnState, Weapon::Anim::AIM, 0.0f, 1.0f); if (arm.target > -1 || ((input & ACTION) && arm.tracking == -1)) {
if (arm.anim == Weapon::Anim::HOLD)
wpnSetAnim(arm, wpnState, Weapon::Anim::AIM, 0.0f, 1.0f);
} else } else
if (arms[i].anim == Weapon::Anim::AIM) if (arm.anim == Weapon::Anim::AIM)
arms[i].animation.dir = -1.0f; arm.animation.dir = -1.0f;
if (isRifle) break; if (isRifle) break;
} }
@@ -1003,22 +1007,32 @@ struct Lara : Character {
void aimShotgun() { void aimShotgun() {
quat rot; quat rot;
if (!aim(target, 14, vec4(-PI * 0.4f, PI * 0.4f, -PI * 0.25f, PI * 0.25f), rot, &arms[0].rotAbs))
arms[0].target = -1; Arm &arm = arms[0];
arm.target = aim(arm.target, 14, vec4(-PI * 0.4f, PI * 0.4f, -PI * 0.25f, PI * 0.25f), rot, &arm.rotAbs) ? arm.target : -1;
} }
void aimPistols() { void aimPistols() {
float speed = 8.0f * Core::deltaTime; float speed = 8.0f * Core::deltaTime;
for (int i = 0; i < 2; i++) { int joints[2] = { 8, 11 };
int joint = i ? 11 : 8;
vec4 range = i ? vec4(-PI * 0.4f, PI * 0.4f, -PI * 0.5f, PI * 0.2f) : vec4(-PI * 0.4f, PI * 0.4f, -PI * 0.2f, PI * 0.5f);
Arm &arm = arms[i]; vec4 ranges[2] = {
vec4(-PI * 0.4f, PI * 0.4f, -PI * 0.2f, PI * 0.5f),
vec4(-PI * 0.4f, PI * 0.4f, -PI * 0.5f, PI * 0.2f),
};
for (int i = 0; i < 2; i++) {
quat rot; quat rot;
if (!aim(target, joint, range, rot, &arm.rotAbs)) { Arm &arm = arms[i];
arm.target = -1; int j = joints[i];
rot = quat(0, 0, 0, 1);
if (!aim(arm.target, j, ranges[i], rot, &arm.rotAbs)) {
arm.target = arms[i^1].target;
if (!aim(arm.target, j, ranges[i], rot, &arm.rotAbs)) {
rot = quat(0, 0, 0, 1);
arm.target = -1;
}
} }
float t; float t;
@@ -1030,33 +1044,81 @@ struct Lara : Character {
t = 0.0f; t = 0.0f;
arm.rot = arm.rot.slerp(rot, speed); arm.rot = arm.rot.slerp(rot, speed);
animation.overrides[joint] = animation.overrides[joint].slerp(arm.rot * animation.overrides[joint], t); animation.overrides[j] = animation.overrides[j].slerp(arm.rot * animation.overrides[j], t);
} }
} }
void updateTargets() { void updateTargets() {
arms[0].target = arms[1].target = -1;
if (emptyHands() || !wpnReady()) { if (emptyHands() || !wpnReady()) {
target = arms[0].target = arms[1].target = -1; arms[0].tracking = arms[1].tracking = -1;
return; return;
} }
int count = wpnCurrent != Weapon::SHOTGUN ? 2 : 1;
if (!(input & ACTION)) { if (!(input & ACTION)) {
target = getTarget(); getTargets(arms[0].tracking, arms[1].tracking);
arms[0].target = arms[1].target = target; if (count == 1)
} else arms[1].tracking = -1;
if (target > -1) { else if (arms[0].tracking == -1 && arms[1].tracking != -1)
TR::Entity &e = level->entities[target]; arms[0].tracking = arms[1].tracking;
vec3 to = ((Controller*)e.controller)->pos; else if (arms[1].tracking == -1 && arms[0].tracking != -1)
vec3 from = pos - vec3(0, 512, 0); arms[1].tracking = arms[0].tracking;
arms[0].target = arms[1].target = checkOcclusion(from, to, (to - from).length()) ? target : -1; arms[0].target = arms[0].tracking;
arms[1].target = arms[1].tracking;
} else {
if (arms[0].tracking == -1 && arms[1].tracking == -1)
return;
// flip left and right by relative target direction
if (count > 1) {
int side[2] = { 0, 0 };
vec3 dir = getDir();
dir.y = 0.0f;
for (int i = 0; i < count; i++)
if (arms[i].tracking != -1) {
vec3 v = ((Controller*)level->entities[arms[i].tracking].controller)->pos - pos;
v.y = 0;
side[i] = sign(v.cross(dir).y);
}
if (side[0] > 0 && side[1] < 0)
swap(arms[0].tracking, arms[1].tracking);
} }
// check occlusion for tracking targets
for (int i = 0; i < count; i++)
if (arms[i].tracking > -1) {
TR::Entity &e = level->entities[arms[i].tracking];
Controller *enemy = (Controller*)e.controller;
Box box = enemy->getBoundingBox();
vec3 to = box.center();
to.y = box.min.y + (box.max.y - box.min.y) / 3.0f;
vec3 from = pos - vec3(0, 650, 0);
arms[i].target = checkOcclusion(from, to, (to - from).length()) ? arms[i].tracking : -1;
}
if (count == 1)
arms[1].target = -1;
else if (arms[0].target == -1 && arms[1].target != -1)
arms[0].target = arms[1].target;
else if (arms[1].target == -1 && arms[0].target != -1)
arms[1].target = arms[0].target;
}
} }
int getTarget() { void getTargets(int &target1, int &target2) {
vec3 dir = getDir().normal(); vec3 dir = getDir().normal();
float dist = TARGET_MAX_DIST; float dist[2] = { TARGET_MAX_DIST, TARGET_MAX_DIST };
target1 = target2 = -1;
vec3 from = pos - vec3(0, 650, 0);
int index = -1;
for (int i = 0; i < level->entitiesCount; i++) { for (int i = 0; i < level->entitiesCount; i++) {
TR::Entity &e = level->entities[i]; TR::Entity &e = level->entities[i];
if (!e.flags.active || !e.isEnemy()) continue; if (!e.flags.active || !e.isEnemy()) continue;
@@ -1071,13 +1133,23 @@ struct Lara : Character {
if (dir.dot(v.normal()) <= 0.5f) continue; // target is out of sight -60..+60 degrees if (dir.dot(v.normal()) <= 0.5f) continue; // target is out of sight -60..+60 degrees
float d = v.length(); float d = v.length();
if (d < dist && checkOcclusion(pos - vec3(0, 650, 0), p, d) ) {
index = i; if ((d > dist[0] && d > dist[1]) || !checkOcclusion(from, p, d))
dist = d; continue;
if (d < dist[0]) {
target2 = target1;
dist[1] = dist[0];
target1 = i;
dist[0] = d;
} else if (d < dist[1]) {
target2 = i;
dist[1] = d;
} }
} }
return index; if (target2 == -1 || dist[1] > dist[0] * 4)
target2 = target1;
} }
bool checkOcclusion(const vec3 &from, const vec3 &to, float dist) { bool checkOcclusion(const vec3 &from, const vec3 &to, float dist) {