751 lines
20 KiB
C++
Raw Normal View History

2013-08-29 11:45:22 +09:00
/*
Copyright (c) 2013 yvt
2016-11-20 19:13:00 +09:00
2013-08-29 11:45:22 +09:00
This file is part of OpenSpades.
2016-11-20 19:13:00 +09:00
2013-08-29 11:45:22 +09:00
OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
2016-11-20 19:13:00 +09:00
2013-08-29 11:45:22 +09:00
OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
2016-11-20 19:13:00 +09:00
2013-08-29 11:45:22 +09:00
You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
2016-11-20 19:13:00 +09:00
2013-08-29 11:45:22 +09:00
*/
2013-08-18 16:18:06 +09:00
#include "Corpse.h"
#include <Core/Debug.h>
#include <Core/Settings.h>
2013-08-18 16:18:06 +09:00
#include "GameMap.h"
#include "IModel.h"
2013-08-18 16:18:06 +09:00
#include "IRenderer.h"
#include "Player.h"
#include "World.h"
2016-03-07 09:37:15 +10:30
using namespace std;
2016-11-19 21:03:51 +09:00
DEFINE_SPADES_SETTING(r_corpseLineCollision, "1");
2013-08-18 16:18:06 +09:00
namespace spades {
namespace client {
Corpse::Corpse(IRenderer *renderer, GameMap *map, Player *p)
: renderer(renderer), map(map) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
playerId = p->GetId();
2013-08-18 16:18:06 +09:00
IntVector3 col = p->GetWorld()->GetTeam(p->GetTeamId()).color;
color = MakeVector3(col.x / 255.f, col.y / 255.f, col.z / 255.f);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
bool crouch = p->GetInput().crouch;
Vector3 front = p->GetFront();
2016-11-20 19:13:00 +09:00
2013-09-20 23:03:32 +02:00
float yaw = atan2(front.y, front.x) + static_cast<float>(M_PI) * .5f;
// float pitch = -atan2(front.z, sqrt(front.x * front.x + front.y * front.y));
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
// lower axis
Matrix4 lower = Matrix4::Translate(p->GetOrigin());
lower = lower * Matrix4::Rotate(MakeVector3(0, 0, 1), yaw);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Matrix4 torso;
2016-11-20 19:13:00 +09:00
if (crouch) {
2013-09-20 23:03:32 +02:00
lower = lower * Matrix4::Translate(0, 0, -0.4f);
torso = lower * Matrix4::Translate(0, 0, -0.3f);
2016-11-20 19:13:00 +09:00
SetNode(Torso1, torso * MakeVector3(0.4f, -.15f, 0.1f));
SetNode(Torso2, torso * MakeVector3(-0.4f, -.15f, 0.1f));
SetNode(Torso3, torso * MakeVector3(-0.4f, .8f, 0.7f));
SetNode(Torso4, torso * MakeVector3(0.4f, .8f, 0.7f));
2016-11-20 19:13:00 +09:00
SetNode(Leg1, lower * MakeVector3(-0.4f, .1f, 1.f));
SetNode(Leg2, lower * MakeVector3(0.4f, .1f, 1.f));
2016-11-20 19:13:00 +09:00
SetNode(Arm1, torso * MakeVector3(0.2f, -.4f, .2f));
SetNode(Arm2, torso * MakeVector3(-0.2f, -.4f, .2f));
2016-11-20 19:13:00 +09:00
} else {
torso = lower * Matrix4::Translate(0, 0, -1.1f);
2016-11-20 19:13:00 +09:00
SetNode(Torso1, torso * MakeVector3(0.4f, 0.f, 0.1f));
SetNode(Torso2, torso * MakeVector3(-0.4f, 0.f, 0.1f));
SetNode(Torso3, torso * MakeVector3(-0.4f, .0f, 1.f));
SetNode(Torso4, torso * MakeVector3(0.4f, .0f, 1.f));
2016-11-20 19:13:00 +09:00
SetNode(Leg1, lower * MakeVector3(-0.4f, .0f, 1.f));
SetNode(Leg2, lower * MakeVector3(0.4f, .0f, 1.f));
2016-11-20 19:13:00 +09:00
SetNode(Arm1, torso * MakeVector3(0.2f, -.4f, .2f));
SetNode(Arm2, torso * MakeVector3(-0.2f, -.4f, .2f));
}
2016-11-20 19:13:00 +09:00
SetNode(Head,
(nodes[Torso1].pos + nodes[Torso2].pos) * .5f + MakeVector3(0, 0, -0.6f));
2013-08-18 16:18:06 +09:00
}
2016-11-20 19:13:00 +09:00
void Corpse::SetNode(NodeType n, spades::Vector3 v) {
auto velNoise = [&] { return (SampleRandomFloat() - SampleRandomFloat()) * 2.0f; };
SPAssert(n >= 0);
SPAssert(n < NodeCount);
2013-08-18 16:18:06 +09:00
nodes[n].pos = v;
nodes[n].vel = MakeVector3(velNoise(), velNoise(), 0.f);
2013-08-18 16:18:06 +09:00
nodes[n].lastPos = v;
nodes[n].lastForce = MakeVector3(0, 0, 0);
2013-08-18 16:18:06 +09:00
}
void Corpse::SetNode(NodeType n, spades::Vector4 v) {
SetNode(n, v.GetXYZ());
}
2016-11-20 19:13:00 +09:00
Corpse::~Corpse() {}
2016-11-20 19:13:00 +09:00
void Corpse::Spring(NodeType n1, NodeType n2, float distance, float dt) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION_DEBUG();
SPAssert(n1 >= 0);
SPAssert(n1 < NodeCount);
SPAssert(n2 >= 0);
SPAssert(n2 < NodeCount);
Node &a = nodes[n1];
Node &b = nodes[n2];
2013-08-18 16:18:06 +09:00
Vector3 diff = b.pos - a.pos;
float dist = diff.GetLength();
Vector3 force = diff.Normalize() * (distance - dist);
force *= dt * 50.f;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
b.vel += force;
a.vel -= force;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
b.pos += force / (dt * 50.f) * 0.5f;
a.pos -= force / (dt * 50.f) * 0.5f;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 velMid = (a.vel + b.vel) * .5f;
float dump = 1.f - powf(.1f, dt);
a.vel += (velMid - a.vel) * dump;
b.vel += (velMid - b.vel) * dump;
}
void Corpse::Spring(NodeType n1a, NodeType n1b, NodeType n2, float distance, float dt) {
2013-08-18 16:18:06 +09:00
SPADES_MARK_FUNCTION_DEBUG();
SPAssert(n1a >= 0);
SPAssert(n1a < NodeCount);
SPAssert(n1b >= 0);
SPAssert(n1b < NodeCount);
SPAssert(n2 >= 0);
SPAssert(n2 < NodeCount);
Node &x = nodes[n1a];
Node &y = nodes[n1b];
Node &b = nodes[n2];
2013-08-18 16:18:06 +09:00
Vector3 diff = b.pos - (x.pos + y.pos) * .5f;
float dist = diff.GetLength();
Vector3 force = diff.Normalize() * (distance - dist);
force *= dt * 50.f;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
b.vel += force;
force *= .5f;
x.vel -= force;
y.vel -= force;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 velMid = (x.vel + y.vel) * .25f + b.vel * .5f;
float dump = 1.f - powf(.05f, dt);
x.vel += (velMid - x.vel) * dump;
y.vel += (velMid - y.vel) * dump;
b.vel += (velMid - b.vel) * dump;
}
2016-11-20 19:13:00 +09:00
static float MyACos(float v) {
2016-11-18 04:44:57 -08:00
SPAssert(!isnan(v));
if (v >= 1.f)
return 0.f;
if (v <= -1.f)
return static_cast<float>(M_PI);
2013-08-18 16:18:06 +09:00
float vv = acosf(v);
if (isnan(vv)) {
2013-08-18 16:18:06 +09:00
vv = acosf(v * .9999f);
}
2016-11-18 04:44:57 -08:00
SPAssert(!isnan(vv));
2013-08-18 16:18:06 +09:00
return vv;
}
void Corpse::AngleSpring(NodeType base, NodeType n1id, NodeType n2id, float minDot,
float maxDot, float dt) {
Node &nBase = nodes[base];
Node &n1 = nodes[n1id];
Node &n2 = nodes[n2id];
2013-08-18 16:18:06 +09:00
Vector3 d1 = n1.pos - nBase.pos;
Vector3 d2 = n2.pos - nBase.pos;
float ln1 = d1.GetLength();
float ln2 = d2.GetLength();
float dot = Vector3::Dot(d1, d2) / (ln1 * ln2 + 0.0000001f);
2016-11-20 19:13:00 +09:00
if (dot >= minDot && dot <= maxDot)
2013-08-18 16:18:06 +09:00
return;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 diff = n2.pos - n1.pos;
float strength = 0.f;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 a1 = Vector3::Cross(d1, diff);
a1 = Vector3::Cross(d1, a1).Normalize();
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 a2 = Vector3::Cross(d2, diff);
a2 = Vector3::Cross(d2, a2).Normalize();
2016-11-20 19:13:00 +09:00
// a1=-a1; a2=-a2;
// a1 = -a1;
2013-08-18 16:18:06 +09:00
a2 = -a2;
2016-11-20 19:13:00 +09:00
if (dot > maxDot) {
2013-08-18 16:18:06 +09:00
strength = MyACos(dot) - MyACos(maxDot);
} else if (dot < minDot) {
2013-08-18 16:18:06 +09:00
strength = MyACos(dot) - MyACos(minDot);
}
2016-11-20 19:13:00 +09:00
2016-11-18 04:44:57 -08:00
SPAssert(!isnan(strength));
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
strength *= 20.f;
strength *= dt;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
a1 *= strength;
a2 *= strength;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
a2 *= 0.f;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
n2.vel += a1;
n1.vel += a2;
nBase.vel -= a1 + a2;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
/*
d1 += a1 * 0.01;
d2 += a2 * 0.01;
float nd = Vector3::Dot(d1, d2) / (d1.GetLength() * d2.GetLength());
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
if(dot > maxDot){
if(nd < dot)
printf("GOOD %f -> %f\n", dot, nd);
else
printf("BAD %f -> %f\n", dot, nd);
2013-08-18 16:18:06 +09:00
}else{
if(nd > dot)
printf("GOOD %f -> %f\n", dot, nd);
else
printf("BAD %f -> %f\n", dot, nd);
2013-08-18 16:18:06 +09:00
}*/
}
void Corpse::AngleSpring(NodeType n1id, NodeType n2id, Vector3 dir, float minDot,
float maxDot, float dt) {
Node &n1 = nodes[n1id];
Node &n2 = nodes[n2id];
2013-08-18 16:18:06 +09:00
Vector3 diff = n2.pos - n1.pos;
float ln1 = diff.GetLength();
float dot = Vector3::Dot(diff, dir) / (ln1 + 0.000000001f);
2016-11-20 19:13:00 +09:00
if (dot >= minDot && dot <= maxDot)
2013-08-18 16:18:06 +09:00
return;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
float strength = 0.f;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 a1 = Vector3::Cross(dir, diff);
a1 = Vector3::Cross(diff, a1).Normalize();
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 a2 = -a1;
// a1=-a1; a2=-a2;
// a1 = -a1;
2016-11-20 19:13:00 +09:00
if (dot > maxDot) {
2013-08-18 16:18:06 +09:00
strength = MyACos(dot) - MyACos(maxDot);
} else if (dot < minDot) {
2013-08-18 16:18:06 +09:00
strength = MyACos(dot) - MyACos(minDot);
}
2016-11-20 19:13:00 +09:00
2016-11-18 04:44:57 -08:00
SPAssert(!isnan(strength));
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
strength *= 100.f;
strength *= dt;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
a1 *= strength;
a2 *= strength;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
n2.vel += a1;
n1.vel += a2;
// nBase.vel -= a1 + a2;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
/*
d1 += a1 * 0.01;
d2 += a2 * 0.01;
float nd = Vector3::Dot(d1, d2) / (d1.GetLength() * d2.GetLength());
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
if(dot > maxDot){
if(nd < dot)
printf("GOOD %f -> %f\n", dot, nd);
else
printf("BAD %f -> %f\n", dot, nd);
}else{
if(nd > dot)
printf("GOOD %f -> %f\n", dot, nd);
else
printf("BAD %f -> %f\n", dot, nd);
}*/
}
2016-11-20 19:13:00 +09:00
static float fractf(float v) { return v - floorf(v); }
2016-11-20 19:13:00 +09:00
static void CheckEscape(GameMap *map, IntVector3 hitBlock, IntVector3 a, IntVector3 b,
IntVector3 dir, float &bestDist, IntVector3 &bestDir) {
hitBlock += dir;
IntVector3 aa = a + dir;
IntVector3 bb = b + dir;
if (map->IsSolidWrapped(hitBlock.x, hitBlock.y, hitBlock.z))
return;
if (map->IsSolidWrapped(aa.x, aa.y, aa.z))
return;
if (map->IsSolidWrapped(bb.x, bb.y, bb.z))
return;
float dist;
if (dir.x == 1) {
dist = 1.f - fractf(a.x);
dist += 1.f - fractf(b.x);
} else if (dir.x == -1) {
dist = fractf(a.x);
dist += fractf(b.x);
} else if (dir.y == 1) {
dist = 1.f - fractf(a.y);
dist += 1.f - fractf(b.y);
} else if (dir.y == -1) {
dist = fractf(a.y);
dist += fractf(b.y);
} else if (dir.z == 1) {
dist = 1.f - fractf(a.z);
dist += 1.f - fractf(b.z);
} else if (dir.z == -1) {
dist = fractf(a.z);
dist += fractf(b.z);
} else {
SPAssert(false);
return;
}
2016-11-20 19:13:00 +09:00
if (dist < bestDist) {
bestDist = dist;
bestDir = dir;
}
}
2016-11-20 19:13:00 +09:00
void Corpse::LineCollision(NodeType a, NodeType b, float dt) {
if (!r_corpseLineCollision)
2013-08-18 16:18:06 +09:00
return;
Node &n1 = nodes[a];
Node &n2 = nodes[b];
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
IntVector3 hitBlock;
2016-11-20 19:13:00 +09:00
if (map->CastRay(n1.lastPos, n2.lastPos, 16.f, hitBlock)) {
GameMap::RayCastResult res1 = map->CastRay2(n1.lastPos, n2.lastPos - n1.lastPos, 8);
GameMap::RayCastResult res2 = map->CastRay2(n2.lastPos, n1.lastPos - n2.lastPos, 8);
2016-11-20 19:13:00 +09:00
if (!res1.hit)
return;
if (!res2.hit)
return;
if (res1.startSolid || res2.startSolid) {
return;
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
// really hit?
if (Vector3::Dot(res1.hitPos - n1.lastPos, n2.lastPos - n1.lastPos) >
(n2.pos - n1.pos).GetPoweredLength()) {
2013-08-18 16:18:06 +09:00
return;
}
if (Vector3::Dot(res1.hitPos - n1.lastPos, n2.lastPos - n1.lastPos) < 0.f) {
2013-08-18 16:18:06 +09:00
return;
}
if (Vector3::Dot(res2.hitPos - n2.lastPos, n1.lastPos - n2.lastPos) >
(n2.pos - n1.pos).GetPoweredLength()) {
2013-08-18 16:18:06 +09:00
return;
}
if (Vector3::Dot(res2.hitPos - n2.lastPos, n1.lastPos - n2.lastPos) < 0.f) {
2013-08-18 16:18:06 +09:00
return;
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 blockPos;
blockPos.x = hitBlock.x + .5f;
blockPos.y = hitBlock.y + .5f;
blockPos.z = hitBlock.z + .5f;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
float inlen = (res1.hitPos - res2.hitPos).GetLength();
2016-11-20 19:13:00 +09:00
IntVector3 ivec = {0, 0, 0};
2016-11-20 19:13:00 +09:00
ivec.x += res1.normal.x;
ivec.y += res1.normal.y;
ivec.z += res1.normal.z;
ivec.x += res2.normal.x;
ivec.y += res2.normal.y;
ivec.z += res2.normal.z;
2016-11-20 19:13:00 +09:00
Vector3 dir = {0.f, 0.f, 0.f};
if (ivec.x == 0 && ivec.y == 0 && ivec.z == 0) {
// hanging. which direction to escape?
float bestDist = 1000.f;
IntVector3 bestDir;
CheckEscape(map, hitBlock, n1.pos.Floor(), n2.pos.Floor(),
IntVector3::Make(1, 0, 0), bestDist, bestDir);
CheckEscape(map, hitBlock, n1.pos.Floor(), n2.pos.Floor(),
IntVector3::Make(-1, 0, 0), bestDist, bestDir);
CheckEscape(map, hitBlock, n1.pos.Floor(), n2.pos.Floor(),
IntVector3::Make(0, 1, 0), bestDist, bestDir);
CheckEscape(map, hitBlock, n1.pos.Floor(), n2.pos.Floor(),
IntVector3::Make(0, -1, 0), bestDist, bestDir);
CheckEscape(map, hitBlock, n1.pos.Floor(), n2.pos.Floor(),
IntVector3::Make(0, 0, 1), bestDist, bestDir);
CheckEscape(map, hitBlock, n1.pos.Floor(), n2.pos.Floor(),
IntVector3::Make(0, 0, -1), bestDist, bestDir);
if (bestDist > 10.f) {
// failed to find appropriate direction.
return;
}
ivec = bestDir;
inlen = bestDist + .1f;
}
dir.x = ivec.x;
dir.y = ivec.y;
dir.z = ivec.z;
2016-11-20 19:13:00 +09:00
Vector3 normDir = dir; // |D|
2016-11-20 19:13:00 +09:00
n1.vel -= normDir * std::min(Vector3::Dot(normDir, n1.vel), 0.f);
n2.vel -= normDir * std::min(Vector3::Dot(normDir, n2.vel), 0.f);
2016-11-20 19:13:00 +09:00
dir *= dt * inlen * 5.f;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
n1.vel += dir;
n2.vel += dir;
2016-11-20 19:13:00 +09:00
// friction
n1.vel -= (n1.vel - normDir * Vector3::Dot(normDir, n1.vel)) * .2f;
n2.vel -= (n2.vel - normDir * Vector3::Dot(normDir, n2.vel)) * .2f;
2013-08-18 16:18:06 +09:00
}
}
2016-11-20 19:13:00 +09:00
void Corpse::AngularMomentum(int eId, NodeType a, NodeType b) {
Edge &e = edges[eId];
2013-09-13 01:33:51 +09:00
e.velDiff = nodes[b].vel - nodes[a].vel;
if (e.node1 != a || e.node2 != b) {
2013-09-13 01:33:51 +09:00
e.lastVelDiff = e.velDiff;
e.node1 = a;
e.node2 = b;
2013-09-13 01:33:51 +09:00
return;
}
2016-11-20 19:13:00 +09:00
2013-09-13 01:33:51 +09:00
Vector3 force = e.lastVelDiff - e.velDiff;
force *= .5f;
nodes[b].vel += force;
nodes[a].vel -= force;
2016-11-20 19:13:00 +09:00
2013-09-13 01:33:51 +09:00
e.lastVelDiff = e.velDiff;
}
2013-08-18 16:18:06 +09:00
void Corpse::ApplyConstraint(float dt) {
SPADES_MARK_FUNCTION();
2016-11-20 19:13:00 +09:00
AngularMomentum(0, Torso1, Torso2);
AngularMomentum(1, Torso2, Torso3);
AngularMomentum(2, Torso3, Torso4);
AngularMomentum(3, Torso4, Torso1);
AngularMomentum(4, Torso1, Arm1);
AngularMomentum(5, Torso2, Arm2);
AngularMomentum(6, Torso3, Leg1);
AngularMomentum(7, Torso4, Leg2);
2016-11-20 19:13:00 +09:00
Spring(Torso1, Torso2, 0.8f, dt);
Spring(Torso3, Torso4, 0.8f, dt);
2016-11-20 19:13:00 +09:00
Spring(Torso1, Torso4, 0.9f, dt);
Spring(Torso2, Torso3, 0.9f, dt);
Spring(Torso1, Torso3, 1.204f, dt);
Spring(Torso2, Torso4, 1.204f, dt);
Spring(Arm1, Torso1, 1.f, dt);
Spring(Arm2, Torso2, 1.f, dt);
Spring(Leg1, Torso3, 1.f, dt);
Spring(Leg2, Torso4, 1.f, dt);
AngleSpring(Torso1, Arm1, Torso3, -1.f, 0.6f, dt);
AngleSpring(Torso2, Arm2, Torso4, -1.f, 0.6f, dt);
AngleSpring(Torso3, Leg1, Torso2, -1.f, -0.2f, dt);
AngleSpring(Torso4, Leg2, Torso1, -1.f, -0.2f, dt);
Spring(Torso1, Torso2, Head, .6f, dt);
2013-08-18 16:18:06 +09:00
/*
AngleSpring(Torso1,
Torso2, Head,
0.5f, 1.f, dt);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
AngleSpring(Torso2,
Torso1, Head,
0.5f, 1.f, dt);
2013-08-18 16:18:06 +09:00
*/
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
LineCollision(Torso1, Torso2, dt);
LineCollision(Torso2, Torso3, dt);
LineCollision(Torso3, Torso4, dt);
LineCollision(Torso4, Torso1, dt);
LineCollision(Torso1, Torso3, dt);
LineCollision(Torso2, Torso4, dt);
LineCollision(Torso1, Arm1, dt);
LineCollision(Torso2, Arm2, dt);
LineCollision(Torso3, Leg1, dt);
LineCollision(Torso4, Leg2, dt);
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
void Corpse::Update(float dt) {
SPADES_MARK_FUNCTION();
float damp = 1.f;
2016-11-20 19:13:00 +09:00
float damp2 = 1.f;
if (dt > 0.f) {
damp = powf(.9f, dt);
2013-09-13 00:44:54 +09:00
damp2 = powf(.371f, dt);
2016-11-20 19:13:00 +09:00
}
// dt *= 0.1f;
2016-11-20 19:13:00 +09:00
for (int i = 0; i < NodeCount; i++) {
Node &node = nodes[i];
2013-08-18 16:18:06 +09:00
Vector3 oldPos = node.lastPos;
node.pos += node.vel * dt;
2016-11-20 19:13:00 +09:00
2016-11-18 04:44:57 -08:00
SPAssert(!isnan(node.pos.x));
SPAssert(!isnan(node.pos.y));
SPAssert(!isnan(node.pos.z));
2016-11-20 19:13:00 +09:00
if (node.pos.z > 63.f) {
2013-08-18 16:18:06 +09:00
node.vel.z -= dt * 6.f; // buoyancy
node.vel *= damp;
} else {
2016-11-20 19:13:00 +09:00
node.vel.z += dt * 32.f; // gravity
node.vel.z *= damp2;
}
// node.vel *= damp;
2016-11-20 19:13:00 +09:00
if (!map->ClipBox(oldPos.x, oldPos.y, oldPos.z)) {
2016-11-20 19:13:00 +09:00
if (map->ClipBox(node.pos.x, oldPos.y, oldPos.z)) {
2013-08-18 16:18:06 +09:00
node.vel.x = -node.vel.x * .2f;
if (fabsf(node.vel.x) < .3f)
2013-08-18 16:18:06 +09:00
node.vel.x = 0.f;
node.pos.x = oldPos.x;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
node.vel.y *= .5f;
node.vel.z *= .5f;
}
2016-11-20 19:13:00 +09:00
if (map->ClipBox(node.pos.x, node.pos.y, oldPos.z)) {
2013-08-18 16:18:06 +09:00
node.vel.y = -node.vel.y * .2f;
if (fabsf(node.vel.y) < .3f)
2013-08-18 16:18:06 +09:00
node.vel.y = 0.f;
node.pos.y = oldPos.y;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
node.vel.x *= .5f;
node.vel.z *= .5f;
}
2016-11-20 19:13:00 +09:00
if (map->ClipBox(node.pos.x, node.pos.y, node.pos.z)) {
2013-08-18 16:18:06 +09:00
node.vel.z = -node.vel.z * .2f;
if (fabsf(node.vel.z) < .3f)
2013-08-18 16:18:06 +09:00
node.vel.z = 0.f;
node.pos.z = oldPos.z;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
node.vel.x *= .5f;
node.vel.y *= .5f;
}
2016-11-20 19:13:00 +09:00
if (map->ClipBox(node.pos.x, node.pos.y, node.pos.z)) {
2013-08-18 16:18:06 +09:00
// TODO: getting out block
// node.pos = oldPos;
// node.vel *= .5f;
2013-08-18 16:18:06 +09:00
}
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
/*
if(map->ClipBox(node.pos.x,
node.pos.y,
node.pos.z)){
if(!map->ClipBox(node.pos.x,
node.pos.y,
oldPos.z)){
node.vel.z = -node.vel.z * .2f;
if(fabsf(node.vel.z) < .3f)
node.vel.z = 0.f;
node.pos.z = oldPos.z;
}
if(!map->ClipBox(node.pos.x,
oldPos.y,
node.pos.z)){
node.vel.y = -node.vel.y * .2f;
if(fabsf(node.vel.y) < .3f)
node.vel.y = 0.f;
node.pos.y = oldPos.y;
}
if(!map->ClipBox(oldPos.x,
node.pos.y,
node.pos.z)){
node.vel.x = -node.vel.x * .2f;
if(fabsf(node.vel.x) < .3f)
node.vel.x = 0.f;
node.pos.x = oldPos.x;
}
node.vel *= .8f;
//node.pos = oldPos;
if(node.vel.GetLength() < .02f){
node.vel *= 0.f;
}
2013-08-18 16:18:06 +09:00
}*/
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
node.lastPos = node.pos;
node.lastForce = node.vel;
}
ApplyConstraint(dt);
2016-11-20 19:13:00 +09:00
for (int i = 0; i < NodeCount; i++) {
2013-08-18 16:18:06 +09:00
nodes[i].lastForce = nodes[i].vel - nodes[i].lastForce;
}
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
void Corpse::AddToScene() {
ModelRenderParam param;
param.customColor = color;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
IModel *model;
Matrix4 scaler = Matrix4::Scale(.1f);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
// draw torso
Matrix4 torso;
Vector3 tX, tY;
{
Vector3 tX1 = nodes[Torso1].pos - nodes[Torso2].pos;
Vector3 tX2 = nodes[Torso4].pos - nodes[Torso3].pos;
Vector3 tY1 = nodes[Torso1].pos + nodes[Torso2].pos;
Vector3 tY2 = nodes[Torso4].pos + nodes[Torso3].pos;
tX = ((tX1 + tX2) * .5f).Normalize();
tY = ((tY2 - tY1) * .5f).Normalize();
Vector3 tZ = Vector3::Cross(tX, tY).Normalize();
tY = Vector3::Cross(tX, tZ).Normalize();
Vector3 tOrigin = tY1 * .5f;
torso = Matrix4::FromAxis(tX, -tZ, -tY, tOrigin);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
param.matrix = torso * scaler;
2016-11-20 19:13:00 +09:00
model = renderer->RegisterModel("Models/Player/Torso.kv6");
2013-08-18 16:18:06 +09:00
renderer->RenderModel(model, param);
}
// draw Head
{
Vector3 headBase = (torso * MakeVector3(0.0f, 0.f, 0.f)).GetXYZ();
2016-11-20 19:13:00 +09:00
model = renderer->RegisterModel("Models/Player/Head.kv6");
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 aX, aY, aZ;
Vector3 center = (nodes[Torso1].pos + nodes[Torso2].pos) * .5f;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
aZ = nodes[Head].pos - center;
aZ = -torso.GetAxis(2);
aZ = aZ.Normalize();
aY = nodes[Torso2].pos - nodes[Torso1].pos;
aY = Vector3::Cross(aY, aZ).Normalize();
aX = Vector3::Cross(aY, aZ).Normalize();
param.matrix = Matrix4::FromAxis(-aX, aY, -aZ, headBase) * scaler;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
renderer->RenderModel(model, param);
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
// draw Arms
{
Vector3 arm1Base = (torso * MakeVector3(0.4f, 0.f, 0.2f)).GetXYZ();
Vector3 arm2Base = (torso * MakeVector3(-0.4f, 0.f, 0.2f)).GetXYZ();
2016-11-20 19:13:00 +09:00
model = renderer->RegisterModel("Models/Player/Arm.kv6");
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 aX, aY, aZ;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
aZ = nodes[Arm1].pos - nodes[Torso1].pos;
aZ = aZ.Normalize();
aY = nodes[Torso2].pos - nodes[Torso1].pos;
aY = Vector3::Cross(aY, aZ).Normalize();
aX = Vector3::Cross(aY, aZ).Normalize();
param.matrix = Matrix4::FromAxis(aX, aY, aZ, arm1Base) * scaler;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
renderer->RenderModel(model, param);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
aZ = nodes[Arm2].pos - nodes[Torso2].pos;
aZ = aZ.Normalize();
aY = nodes[Torso1].pos - nodes[Torso2].pos;
aY = Vector3::Cross(aY, aZ).Normalize();
aX = Vector3::Cross(aY, aZ).Normalize();
param.matrix = Matrix4::FromAxis(aX, aY, aZ, arm2Base) * scaler;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
renderer->RenderModel(model, param);
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
// draw Leg
{
Vector3 leg1Base = (torso * MakeVector3(0.25f, 0.f, 0.9f)).GetXYZ();
Vector3 leg2Base = (torso * MakeVector3(-0.25f, 0.f, 0.9f)).GetXYZ();
2016-11-20 19:13:00 +09:00
model = renderer->RegisterModel("Models/Player/Leg.kv6");
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 aX, aY, aZ;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
aZ = nodes[Leg1].pos - nodes[Torso3].pos;
aZ = aZ.Normalize();
aY = nodes[Torso1].pos - nodes[Torso2].pos;
aY = Vector3::Cross(aY, aZ).Normalize();
aX = Vector3::Cross(aY, aZ).Normalize();
param.matrix = Matrix4::FromAxis(aX, aY, aZ, leg1Base) * scaler;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
renderer->RenderModel(model, param);
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
aZ = nodes[Leg2].pos - nodes[Torso4].pos;
aZ = aZ.Normalize();
aY = nodes[Torso1].pos - nodes[Torso2].pos;
aY = Vector3::Cross(aY, aZ).Normalize();
aX = Vector3::Cross(aY, aZ).Normalize();
param.matrix = Matrix4::FromAxis(aX, aY, aZ, leg2Base) * scaler;
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
renderer->RenderModel(model, param);
}
}
2016-11-20 19:13:00 +09:00
2013-08-18 16:18:06 +09:00
Vector3 Corpse::GetCenter() {
Vector3 v = {0, 0, 0};
for (int i = 0; i < NodeCount; i++)
2013-08-18 16:18:06 +09:00
v += nodes[i].pos;
v *= 1.f / (float)NodeCount;
return v;
}
2016-11-20 19:13:00 +09:00
bool Corpse::IsVisibleFrom(spades::Vector3 eye) {
2013-08-18 16:18:06 +09:00
// distance culled?
if ((eye - GetCenter()).GetLength() > 150.f)
2013-08-18 16:18:06 +09:00
return false;
2016-11-20 19:13:00 +09:00
for (int i = 0; i < NodeCount; i++) {
2013-08-18 16:18:06 +09:00
IntVector3 outBlk;
if (map->CastRay(eye, nodes[i].pos, 256.f, outBlk))
2013-08-18 16:18:06 +09:00
return true;
}
return false;
}
2016-11-20 19:13:00 +09:00
void Corpse::AddImpulse(spades::Vector3 v) {
for (int i = 0; i < NodeCount; i++)
2013-08-18 16:18:06 +09:00
nodes[i].vel += v;
}
}
}