From cc308e255aa82eb82407fd65a2faf659f68680df Mon Sep 17 00:00:00 2001 From: XProger Date: Wed, 6 Sep 2017 17:30:32 +0300 Subject: [PATCH] #22 add boulder trap, add sprites velocity; #8 fix camera targeting --- src/camera.h | 37 ++++++++-------- src/controller.h | 5 ++- src/debug.h | 2 +- src/lara.h | 108 +++++++++++++++++++++++++++++------------------ src/level.h | 4 +- src/sprite.h | 5 ++- src/trigger.h | 58 ++++++++++++++++++++++--- 7 files changed, 147 insertions(+), 72 deletions(-) diff --git a/src/camera.h b/src/camera.h index 6f327bc..7db21be 100644 --- a/src/camera.h +++ b/src/camera.h @@ -58,7 +58,7 @@ struct Camera : ICamera { } virtual int getRoomIndex() const { - return viewIndex > -1 ? level->cameras[viewIndex].room : room; + return room; } virtual void checkRoom() { @@ -114,6 +114,9 @@ struct Camera : ICamera { this->timer = timer; this->speed = speed; lastDest = pos; + + if (viewIndex > -1) + room = level->cameras[viewIndex].room; } vec3 getViewPoint() { @@ -125,6 +128,14 @@ struct Camera : ICamera { return p; } + void resetTarget(const vec3 &viewPoint) { + timer = -1.0f; + state = STATE_FOLLOW; + viewTarget = NULL; + viewIndex = -1; + target = viewPoint; + } + virtual void update() { if (shake > 0.0f) shake = max(0.0f, shake - Core::deltaTime); @@ -214,23 +225,6 @@ struct Camera : ICamera { 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) { 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)); @@ -282,6 +276,13 @@ struct Camera : ICamera { } 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) checkRoom(); } diff --git a/src/controller.h b/src/controller.h index da11481..2cecd0b 100644 --- a/src/controller.h +++ b/src/controller.h @@ -23,6 +23,7 @@ struct ICamera { ICamera() : reflectPlane(NULL) {} virtual void setup(bool calcMatrices) {} + virtual int getRoomIndex() const { return TR::NO_ROOM; } }; struct IGame { @@ -247,8 +248,8 @@ struct Controller { e.rotation = angle.y; } - bool insideRoom(const vec3 &pos, int room) const { - TR::Room &r = level->rooms[room]; + bool insideRoom(const vec3 &pos, int roomIndex) const { + TR::Room &r = level->rooms[roomIndex]; 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)); diff --git a/src/debug.h b/src/debug.h index c5fb685..3e3216c 100644 --- a/src/debug.h +++ b/src/debug.h @@ -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); Debug::Draw::text(vec2(16, y += 16), vec4(1.0f), buf); 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); 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); diff --git a/src/lara.h b/src/lara.h index 4f94183..be038fe 100644 --- a/src/lara.h +++ b/src/lara.h @@ -454,7 +454,8 @@ struct Lara : Character { //reset(51, vec3(41015, 3584, 34494), -PI); // level 3a (t-rex) //reset(5, vec3(38643, -3072, 92370), PI * 0.5f); // level 3a (gears) //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(0, vec3(40913, -1012, 42252), PI); // level 8c //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); Controller *c = Controller::first; - while (c) { - if (level->entities[c->entity].isEnemy()) { - Character *enemy = (Character*)c; - if (enemy->health > 0) { + do { + if (!level->entities[c->entity].isEnemy()) + continue; - Box box = enemy->getBoundingBox(); - vec3 p = box.center(); - p.y = box.min.y + (box.max.y - box.min.y) / 3.0f; + Character *enemy = (Character*)c; + if (enemy->health <= 0) + 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; - if (dir.dot(v.normal()) > 0.5f) { // target is on sight -60..+60 degrees + vec3 v = p - pos; + 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]) { - target2 = target1; - dist[1] = dist[0]; - target1 = enemy; - dist[0] = d; - } else if (d < dist[1]) { - target2 = enemy; - dist[1] = d; - } - } - } - } + if (d < dist[0]) { + target2 = target1; + dist[1] = dist[0]; + target1 = enemy; + dist[0] = d; + } else if (d < dist[1]) { + target2 = enemy; + dist[1] = d; } - - c = c->next; - } + } while ((c = c->next)); if (!target2 || dist[1] > dist[0] * 4) target2 = target1; @@ -1295,16 +1295,42 @@ struct Lara : Character { damageTime = LARA_DAMAGE_TIME; - Character::hit(damage, enemy); - if (damage == REX_DAMAGE) { // T-Rex attack (fatal) - pos = enemy->pos; - angle = enemy->angle; + if (health > 0.0f) { + if (damage == BOULDER_DAMAGE_GROUND) { + if (stand == STAND_GROUND) { + 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); - meshSwap(2, level->extra.weapons[Weapon::SHOTGUN], 0); - meshSwap(3, level->extra.weapons[Weapon::UZIS], 0); + if (damage == REX_DAMAGE) { // T-Rex attack (fatal) + pos = enemy->pos; + 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) @@ -2428,12 +2454,12 @@ struct Lara : Character { } // check enemies & doors - for (int i = 0; i < level->entitiesCount; i++) { - TR::Entity &e = level->entities[i]; - Controller *controller = (Controller*)e.controller; + Controller *controller = Controller::first; + do { + TR::Entity &e = controller->getEntity(); 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 if (!e.isDoor()) continue; @@ -2454,7 +2480,7 @@ struct Lara : Character { 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; if (e.isDoor()) return true; @@ -2468,7 +2494,7 @@ struct Lara : Character { hitDir = angleQuadrant(dir.rotateY(angle.y + PI * 0.5f).angleY()); return true; - } + } while ((controller = controller->next)); hitDir = -1; return false; diff --git a/src/level.h b/src/level.h index 12f1219..3248a35 100644 --- a/src/level.h +++ b/src/level.h @@ -322,10 +322,10 @@ struct Level : IGame { entity.controller = new TrapSpikes(this, i); break; case TR::Entity::TRAP_BOULDER : - entity.controller = new Boulder(this, i); + entity.controller = new TrapBoulder(this, i); break; case TR::Entity::TRAP_DARTGUN : - entity.controller = new Dartgun(this, i); + entity.controller = new TrapDartgun(this, i); break; case TR::Entity::BLOCK_1 : case TR::Entity::BLOCK_2 : diff --git a/src/sprite.h b/src/sprite.h index 9f5aa6e..74d75a2 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -13,8 +13,9 @@ struct Sprite : Controller { bool instant; int frame, flag; 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 this->frame = frame; } else if (frame == FRAME_RANDOM) { // random frame @@ -57,6 +58,8 @@ struct Sprite : Controller { if (instant && time >= (1.0f / SPRITE_FPS)) remove = true; + pos += velocity * Core::deltaTime; + if (remove) { level->entityRemove(entity); delete this; diff --git a/src/trigger.h b/src/trigger.h index 81e7251..5931015 100644 --- a/src/trigger.h +++ b/src/trigger.h @@ -94,13 +94,13 @@ struct Dart : Controller { } }; -struct Dartgun : Controller { +struct TrapDartgun : Controller { enum { STATE_IDLE, STATE_FIRE }; - Dartgun(IGame *game, int entity) : Controller(game, entity) {} + TrapDartgun(IGame *game, int entity) : Controller(game, entity) {} virtual bool 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() { - if (getEntity().flags.active == TR::ACTIVE) { - updateAnimation(true); - updateEntity(); + if (activeState != asActive) return; + + 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(); } };