1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-11 23:54:09 +02:00

#22 add boulder trap, add sprites velocity; #8 fix camera targeting

This commit is contained in:
XProger
2017-09-06 17:30:32 +03:00
parent 56bfc89d2b
commit cc308e255a
7 changed files with 147 additions and 72 deletions

View File

@@ -58,7 +58,7 @@ struct Camera : ICamera {
} }
virtual int getRoomIndex() const { virtual int getRoomIndex() const {
return viewIndex > -1 ? level->cameras[viewIndex].room : room; return room;
} }
virtual void checkRoom() { virtual void checkRoom() {
@@ -114,6 +114,9 @@ struct Camera : ICamera {
this->timer = timer; this->timer = timer;
this->speed = speed; this->speed = speed;
lastDest = pos; lastDest = pos;
if (viewIndex > -1)
room = level->cameras[viewIndex].room;
} }
vec3 getViewPoint() { vec3 getViewPoint() {
@@ -125,6 +128,14 @@ struct Camera : ICamera {
return p; return p;
} }
void resetTarget(const vec3 &viewPoint) {
timer = -1.0f;
state = STATE_FOLLOW;
viewTarget = NULL;
viewIndex = -1;
target = viewPoint;
}
virtual void update() { virtual void update() {
if (shake > 0.0f) if (shake > 0.0f)
shake = max(0.0f, shake - Core::deltaTime); shake = max(0.0f, shake - Core::deltaTime);
@@ -214,23 +225,6 @@ struct Camera : ICamera {
vec3 viewPoint = getViewPoint(); vec3 viewPoint = getViewPoint();
if (timer > 0.0f) {
timer -= Core::deltaTime;
if (timer <= 0.0f) {
timer = -1.0f;
state = STATE_FOLLOW;
viewTarget = owner->viewTarget = NULL;
viewIndex = -1;
target = viewPoint;
if (room != getRoomIndex())
pos = lastDest;
}
} else
viewIndex = -1;
if (timer < 0.0f)
viewTarget = NULL;
if (firstPerson && viewIndex == -1) { if (firstPerson && viewIndex == -1) {
Basis head = owner->animation.getJoints(owner->getMatrix(), 14, true); Basis head = owner->animation.getJoints(owner->getMatrix(), 14, true);
Basis eye(quat(0.0f, 0.0f, 0.0f, 1.0f), vec3(0.0f, -40.0f, 10.0f)); Basis eye(quat(0.0f, 0.0f, 0.0f, 1.0f), vec3(0.0f, -40.0f, 10.0f));
@@ -282,6 +276,13 @@ struct Camera : ICamera {
} }
pos = pos.lerp(destPos, Core::deltaTime * lerpFactor); pos = pos.lerp(destPos, Core::deltaTime * lerpFactor);
if (timer > 0.0f) {
timer -= Core::deltaTime;
if (timer <= 0.0f)
resetTarget(viewPoint);
} else
resetTarget(target);
if (viewIndex == -1) if (viewIndex == -1)
checkRoom(); checkRoom();
} }

View File

@@ -23,6 +23,7 @@ struct ICamera {
ICamera() : reflectPlane(NULL) {} ICamera() : reflectPlane(NULL) {}
virtual void setup(bool calcMatrices) {} virtual void setup(bool calcMatrices) {}
virtual int getRoomIndex() const { return TR::NO_ROOM; }
}; };
struct IGame { struct IGame {
@@ -247,8 +248,8 @@ struct Controller {
e.rotation = angle.y; e.rotation = angle.y;
} }
bool insideRoom(const vec3 &pos, int room) const { bool insideRoom(const vec3 &pos, int roomIndex) const {
TR::Room &r = level->rooms[room]; TR::Room &r = level->rooms[roomIndex];
vec3 min = vec3((float)r.info.x + 1024, (float)r.info.yTop, (float)r.info.z + 1024); vec3 min = vec3((float)r.info.x + 1024, (float)r.info.yTop, (float)r.info.z + 1024);
vec3 max = min + vec3(float((r.xSectors - 1) * 1024), float(r.info.yBottom - r.info.yTop), float((r.zSectors - 1) * 1024)); vec3 max = min + vec3(float((r.xSectors - 1) * 1024), float(r.info.yBottom - r.info.yTop), float((r.zSectors - 1) * 1024));

View File

@@ -658,7 +658,7 @@ namespace Debug {
sprintf(buf, "DIP = %d, TRI = %d, SND = %d, active = %d", Core::stats.dips, Core::stats.tris, Sound::channelsCount, activeCount); sprintf(buf, "DIP = %d, TRI = %d, SND = %d, active = %d", Core::stats.dips, Core::stats.tris, Sound::channelsCount, activeCount);
Debug::Draw::text(vec2(16, y += 16), vec4(1.0f), buf); Debug::Draw::text(vec2(16, y += 16), vec4(1.0f), buf);
vec3 angle = ((Controller*)entity.controller)->angle * RAD2DEG; vec3 angle = ((Controller*)entity.controller)->angle * RAD2DEG;
sprintf(buf, "pos = (%d, %d, %d), angle = (%d, %d), room = %d", entity.x, entity.y, entity.z, (int)angle.x, (int)angle.y, ((Controller*)entity.controller)->getRoomIndex()); sprintf(buf, "pos = (%d, %d, %d), angle = (%d, %d), room = %d (camera: %d)", entity.x, entity.y, entity.z, (int)angle.x, (int)angle.y, ((Controller*)entity.controller)->getRoomIndex(), ((ICamera*)level.cameraController)->getRoomIndex());
Debug::Draw::text(vec2(16, y += 16), vec4(1.0f), buf); Debug::Draw::text(vec2(16, y += 16), vec4(1.0f), buf);
int rate = anim.anims[anim.index].frameRate; int rate = anim.anims[anim.index].frameRate;
sprintf(buf, "state = %d, anim = %d, next = %d, rate = %d, frame = %.2f / %d (%f)", anim.state, anim.index, anim.next, rate, anim.time * 30.0f, anim.framesCount, anim.delta); sprintf(buf, "state = %d, anim = %d, next = %d, rate = %d, frame = %.2f / %d (%f)", anim.state, anim.index, anim.next, rate, anim.time * 30.0f, anim.framesCount, anim.delta);

View File

@@ -454,7 +454,8 @@ struct Lara : Character {
//reset(51, vec3(41015, 3584, 34494), -PI); // level 3a (t-rex) //reset(51, vec3(41015, 3584, 34494), -PI); // level 3a (t-rex)
//reset(5, vec3(38643, -3072, 92370), PI * 0.5f); // level 3a (gears) //reset(5, vec3(38643, -3072, 92370), PI * 0.5f); // level 3a (gears)
//reset(43, vec3(64037, 6656, 48229), PI); // level 3b (movingblock) //reset(43, vec3(64037, 6656, 48229), PI); // level 3b (movingblock)
//reset(5, vec3(73394, 3840, 60758), 0); // level 3b (scion) //reset(5, vec3(73394, 3840, 60758), 0); // level 3b (scion)
//reset(20, vec3(57724, 6656, 61941), 90 * DEG2RAD); // level 3b (boulder)
//reset(99, vec3(45562, -3328, 63366), 225 * DEG2RAD); // level 7a (flipmap) //reset(99, vec3(45562, -3328, 63366), 225 * DEG2RAD); // level 7a (flipmap)
//reset(0, vec3(40913, -1012, 42252), PI); // level 8c //reset(0, vec3(40913, -1012, 42252), PI); // level 8c
//reset(10, vec3(90443, 11264 - 256, 114614), PI, STAND_ONWATER); // villa mortal 2 //reset(10, vec3(90443, 11264 - 256, 114614), PI, STAND_ONWATER); // villa mortal 2
@@ -1181,38 +1182,37 @@ struct Lara : Character {
vec3 from = pos - vec3(0, 650, 0); vec3 from = pos - vec3(0, 650, 0);
Controller *c = Controller::first; Controller *c = Controller::first;
while (c) { do {
if (level->entities[c->entity].isEnemy()) { if (!level->entities[c->entity].isEnemy())
Character *enemy = (Character*)c; continue;
if (enemy->health > 0) {
Box box = enemy->getBoundingBox(); Character *enemy = (Character*)c;
vec3 p = box.center(); if (enemy->health <= 0)
p.y = box.min.y + (box.max.y - box.min.y) / 3.0f; continue;
Box box = enemy->getBoundingBox();
vec3 p = box.center();
p.y = box.min.y + (box.max.y - box.min.y) / 3.0f;
vec3 v = p - pos; vec3 v = p - pos;
if (dir.dot(v.normal()) > 0.5f) { // target is on sight -60..+60 degrees if (dir.dot(v.normal()) <= 0.5f)
continue; // target is out of view range -60..+60 degrees
float d = v.length(); float d = v.length();
if ((d < dist[0] || d < dist[1]) && checkOcclusion(from, p, d)) { if ((d > dist[0] && d > dist[1]) || !checkOcclusion(from, p, d))
continue;
if (d < dist[0]) { if (d < dist[0]) {
target2 = target1; target2 = target1;
dist[1] = dist[0]; dist[1] = dist[0];
target1 = enemy; target1 = enemy;
dist[0] = d; dist[0] = d;
} else if (d < dist[1]) { } else if (d < dist[1]) {
target2 = enemy; target2 = enemy;
dist[1] = d; dist[1] = d;
}
}
}
}
} }
} while ((c = c->next));
c = c->next;
}
if (!target2 || dist[1] > dist[0] * 4) if (!target2 || dist[1] > dist[0] * 4)
target2 = target1; target2 = target1;
@@ -1295,16 +1295,42 @@ struct Lara : Character {
damageTime = LARA_DAMAGE_TIME; damageTime = LARA_DAMAGE_TIME;
Character::hit(damage, enemy); if (health > 0.0f) {
if (damage == REX_DAMAGE) { // T-Rex attack (fatal) if (damage == BOULDER_DAMAGE_GROUND) {
pos = enemy->pos; if (stand == STAND_GROUND) {
angle = enemy->angle; animation.setAnim(level->models[TR::MODEL_LARA_SPEC].animation + 2);
angle = enemy->angle;
TR::Level::FloorInfo info;
level->getFloorInfo(getRoomIndex(), int(pos.x), int(pos.y), int(pos.z), info);
vec3 d = getDir();
vec3 v = info.getSlant(d);
angle.x = -acos(d.dot(v));
int roomIndex = getRoomIndex();
v = ((TrapBoulder*)enemy)->velocity * 60.0f;
for (int i = 0; i < 15; i++) {
vec3 p = pos + vec3(randf() * 512.0f - 256.0f, -randf() * 512.0f, randf() * 512.0f - 256.0f);
int index = Sprite::add(game, TR::Entity::BLOOD, roomIndex, int(p.x), int(p.y), int(p.z), Sprite::FRAME_ANIMATED);
if (index > -1)
((Sprite*)level->entities[index].controller)->velocity = v;
}
} else if (stand == STAND_AIR) {
damage = BOULDER_DAMAGE_AIR * 30.0f * Core::deltaTime;
} else
damage = 0;
}
meshSwap(1, TR::MODEL_LARA_SPEC, BODY_UPPER | BODY_LOWER); if (damage == REX_DAMAGE) { // T-Rex attack (fatal)
meshSwap(2, level->extra.weapons[Weapon::SHOTGUN], 0); pos = enemy->pos;
meshSwap(3, level->extra.weapons[Weapon::UZIS], 0); angle = enemy->angle;
animation.setAnim(level->models[TR::MODEL_LARA_SPEC].animation + 1); meshSwap(1, TR::MODEL_LARA_SPEC, BODY_UPPER | BODY_LOWER);
meshSwap(2, level->extra.weapons[Weapon::SHOTGUN], 0);
meshSwap(3, level->extra.weapons[Weapon::UZIS], 0);
animation.setAnim(level->models[TR::MODEL_LARA_SPEC].animation + 1);
}
Character::hit(damage, enemy);
} }
if (health <= 0) if (health <= 0)
@@ -2428,12 +2454,12 @@ struct Lara : Character {
} }
// check enemies & doors // check enemies & doors
for (int i = 0; i < level->entitiesCount; i++) { Controller *controller = Controller::first;
TR::Entity &e = level->entities[i]; do {
Controller *controller = (Controller*)e.controller; TR::Entity &e = controller->getEntity();
if (e.isEnemy()) { if (e.isEnemy()) {
if (e.type != TR::Entity::ENEMY_REX && (!e.flags.active || ((Character*)e.controller)->health <= 0)) continue; if (e.type != TR::Entity::ENEMY_REX && (!e.flags.active || ((Character*)controller)->health <= 0)) continue;
} else } else
if (!e.isDoor()) continue; if (!e.isDoor()) continue;
@@ -2454,7 +2480,7 @@ struct Lara : Character {
collisionOffset += vec3(p.x, 0.0f, p.z); collisionOffset += vec3(p.x, 0.0f, p.z);
} }
if (e.type == TR::Entity::ENEMY_REX && ((Character*)e.controller)->health <= 0) if (e.type == TR::Entity::ENEMY_REX && ((Character*)controller)->health <= 0)
return true; return true;
if (e.isDoor()) if (e.isDoor())
return true; return true;
@@ -2468,7 +2494,7 @@ struct Lara : Character {
hitDir = angleQuadrant(dir.rotateY(angle.y + PI * 0.5f).angleY()); hitDir = angleQuadrant(dir.rotateY(angle.y + PI * 0.5f).angleY());
return true; return true;
} } while ((controller = controller->next));
hitDir = -1; hitDir = -1;
return false; return false;

View File

@@ -322,10 +322,10 @@ struct Level : IGame {
entity.controller = new TrapSpikes(this, i); entity.controller = new TrapSpikes(this, i);
break; break;
case TR::Entity::TRAP_BOULDER : case TR::Entity::TRAP_BOULDER :
entity.controller = new Boulder(this, i); entity.controller = new TrapBoulder(this, i);
break; break;
case TR::Entity::TRAP_DARTGUN : case TR::Entity::TRAP_DARTGUN :
entity.controller = new Dartgun(this, i); entity.controller = new TrapDartgun(this, i);
break; break;
case TR::Entity::BLOCK_1 : case TR::Entity::BLOCK_1 :
case TR::Entity::BLOCK_2 : case TR::Entity::BLOCK_2 :

View File

@@ -13,8 +13,9 @@ struct Sprite : Controller {
bool instant; bool instant;
int frame, flag; int frame, flag;
float time; float time;
vec3 velocity;
Sprite(IGame *game, int entity, bool instant = true, int frame = FRAME_ANIMATED) : Controller(game, entity), instant(instant), flag(frame), time(0.0f) { Sprite(IGame *game, int entity, bool instant = true, int frame = FRAME_ANIMATED) : Controller(game, entity), instant(instant), flag(frame), time(0), velocity(0) {
if (frame >= 0) { // specific frame if (frame >= 0) { // specific frame
this->frame = frame; this->frame = frame;
} else if (frame == FRAME_RANDOM) { // random frame } else if (frame == FRAME_RANDOM) { // random frame
@@ -57,6 +58,8 @@ struct Sprite : Controller {
if (instant && time >= (1.0f / SPRITE_FPS)) if (instant && time >= (1.0f / SPRITE_FPS))
remove = true; remove = true;
pos += velocity * Core::deltaTime;
if (remove) { if (remove) {
level->entityRemove(entity); level->entityRemove(entity);
delete this; delete this;

View File

@@ -94,13 +94,13 @@ struct Dart : Controller {
} }
}; };
struct Dartgun : Controller { struct TrapDartgun : Controller {
enum { enum {
STATE_IDLE, STATE_IDLE,
STATE_FIRE STATE_FIRE
}; };
Dartgun(IGame *game, int entity) : Controller(game, entity) {} TrapDartgun(IGame *game, int entity) : Controller(game, entity) {}
virtual bool activate() { virtual bool activate() {
if (!Controller::activate()) if (!Controller::activate())
@@ -136,15 +136,59 @@ struct Dartgun : Controller {
} }
}; };
struct Boulder : Controller { #define BOULDER_DAMAGE_GROUND 1001
#define BOULDER_DAMAGE_AIR 100
Boulder(IGame *game, int entity) : Controller(game, entity) {} struct TrapBoulder : Controller {
enum {
STATE_FALL,
STATE_ROLL,
};
vec3 velocity;
TrapBoulder(IGame *game, int entity) : Controller(game, entity), velocity(0) {}
virtual void update() { virtual void update() {
if (getEntity().flags.active == TR::ACTIVE) { if (activeState != asActive) return;
updateAnimation(true);
updateEntity(); TR::Level::FloorInfo info;
level->getFloorInfo(getRoomIndex(), int(pos.x), int(pos.y), int(pos.z), info);
vec3 dir = getDir();
if (pos.y >= info.floor - 256) {
pos.y = info.floor;
velocity = dir * animation.getSpeed();
if (state != STATE_ROLL)
animation.setState(STATE_ROLL);
} else {
if (velocity.y == 0.0f)
velocity.y = 10.0f;
velocity.y += GRAVITY * Core::deltaTime;
animation.setState(STATE_FALL);
} }
vec3 p = pos;
pos += velocity * (30.0f * Core::deltaTime);
if (info.roomNext != TR::NO_ROOM)
getEntity().room = info.roomNext;
vec3 v = pos + getDir() * 512.0f;
level->getFloorInfo(getRoomIndex(), int(v.x), int(v.y), int(v.z), info);
if (pos.y > info.floor) {
pos = p;
deactivate();
return;
}
Controller *lara = (Controller*)level->laraController;
if (collide(lara))
lara->hit(BOULDER_DAMAGE_GROUND, this);
updateAnimation(true);
updateEntity();
} }
}; };