Initial commit
This commit is contained in:
250
engines/scumm/he/basketball/ai.cpp
Normal file
250
engines/scumm/he/basketball/ai.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
|
||||
#include "scumm/he/basketball/ai.h"
|
||||
#include "scumm/he/basketball/basketball.h"
|
||||
#include "scumm/he/basketball/court.h"
|
||||
#include "scumm/he/basketball/geo_translations.h"
|
||||
#include "scumm/he/logic_he.h"
|
||||
|
||||
#include "math/utils.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
int LogicHEBasketball::u32_userGetPlayerClosestToBall(int teamIndex) {
|
||||
assert((TEAM_HOME <= teamIndex) && (teamIndex <= TEAM_AWAY));
|
||||
|
||||
int finalPlayerIndex = NO_PLAYER;
|
||||
int shortestDistance2 = 0x7FFFFFFF;
|
||||
|
||||
// Go through all of the players on the team and calculate the distance between
|
||||
// them and the ball...
|
||||
Common::Array<CCollisionPlayer> *playerList =
|
||||
(teamIndex == TEAM_HOME) ?
|
||||
&_vm->_basketball->_court->_homePlayerList : &_vm->_basketball->_court->_awayPlayerList;
|
||||
|
||||
for (size_t playerIndex = 0; playerIndex < playerList->size(); ++playerIndex) {
|
||||
CCollisionPlayer *currentPlayer = &((*playerList)[playerIndex]);
|
||||
|
||||
if (currentPlayer->_playerIsInGame) {
|
||||
|
||||
int distance2 = (
|
||||
((currentPlayer->center.x - _vm->_basketball->_court->_basketBall.center.x) *
|
||||
(currentPlayer->center.x - _vm->_basketball->_court->_basketBall.center.x)) +
|
||||
((currentPlayer->center.y - _vm->_basketball->_court->_basketBall.center.y) *
|
||||
(currentPlayer->center.y - _vm->_basketball->_court->_basketBall.center.y)));
|
||||
|
||||
// Keep track of the player closest to the ball...
|
||||
if (distance2 < shortestDistance2) {
|
||||
finalPlayerIndex = playerIndex;
|
||||
shortestDistance2 = distance2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(finalPlayerIndex != NO_PLAYER);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, (*playerList)[finalPlayerIndex]._objectID);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userGetPlayerClosestToBall() {
|
||||
int finalPlayerIndex = NO_PLAYER;
|
||||
int shortestDistance2 = 0x7FFFFFFF;
|
||||
Common::Array<CCollisionPlayer> *playerList = nullptr;
|
||||
|
||||
// Go through all of the players on both teams and calculate the distance between
|
||||
// them and the ball...
|
||||
for (size_t playerIndex = 0; playerIndex < _vm->_basketball->_court->_homePlayerList.size(); ++playerIndex) {
|
||||
CCollisionPlayer *currentPlayer = &_vm->_basketball->_court->_homePlayerList[playerIndex];
|
||||
|
||||
if (currentPlayer->_playerIsInGame) {
|
||||
int distance2 = (
|
||||
((currentPlayer->center.x - _vm->_basketball->_court->_basketBall.center.x) *
|
||||
(currentPlayer->center.x - _vm->_basketball->_court->_basketBall.center.x)) +
|
||||
((currentPlayer->center.y - _vm->_basketball->_court->_basketBall.center.y) *
|
||||
(currentPlayer->center.y - _vm->_basketball->_court->_basketBall.center.y)));
|
||||
|
||||
// Keep track of the player closest to the ball...
|
||||
if (distance2 < shortestDistance2) {
|
||||
finalPlayerIndex = playerIndex;
|
||||
shortestDistance2 = distance2;
|
||||
playerList = &_vm->_basketball->_court->_homePlayerList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t playerIndex = 0; playerIndex < _vm->_basketball->_court->_awayPlayerList.size(); ++playerIndex) {
|
||||
CCollisionPlayer *currentPlayer = &_vm->_basketball->_court->_awayPlayerList[playerIndex];
|
||||
|
||||
if (currentPlayer->_playerIsInGame) {
|
||||
int distance2 = (
|
||||
((currentPlayer->center.x - _vm->_basketball->_court->_basketBall.center.x) *
|
||||
(currentPlayer->center.x - _vm->_basketball->_court->_basketBall.center.x)) +
|
||||
((currentPlayer->center.y - _vm->_basketball->_court->_basketBall.center.y) *
|
||||
(currentPlayer->center.y - _vm->_basketball->_court->_basketBall.center.y)));
|
||||
|
||||
// Keep track of the player closest to the ball...
|
||||
if (distance2 < shortestDistance2) {
|
||||
finalPlayerIndex = playerIndex;
|
||||
shortestDistance2 = distance2;
|
||||
playerList = &_vm->_basketball->_court->_awayPlayerList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(finalPlayerIndex != NO_PLAYER);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, (*playerList)[finalPlayerIndex]._objectID);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Basketball::numOpponentsInCone(int team, float widthDistanceRatio, const U32FltVector2D &end, const U32FltVector2D &focus) {
|
||||
// The end out parameter is the end point of the center line of the cone,
|
||||
// and widthDistanceRatio defines the width of the cone = width at dist 1
|
||||
int count = 0;
|
||||
|
||||
Line2D line(focus, end);
|
||||
|
||||
Common::Array<CCollisionPlayer> *playerList = (team == TEAM_HOME) ? &_vm->_basketball->_court->_homePlayerList : &_vm->_basketball->_court->_awayPlayerList;
|
||||
|
||||
for (Common::Array<CCollisionPlayer>::iterator currentPlayer = playerList->begin(); currentPlayer != playerList->end(); ++currentPlayer) {
|
||||
U32FltVector2D point = line.projectPoint(currentPlayer->center);
|
||||
|
||||
if (focus.distance2(currentPlayer->center) < (point.distance2(focus) * widthDistanceRatio * widthDistanceRatio) && line.inBetween(point, focus, end)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool isPointInBounds(const U32FltVector2D &point) {
|
||||
return ((point.x > 0) &&
|
||||
(point.x < MAX_WORLD_X) &&
|
||||
(point.y > 0) &&
|
||||
(point.y < MAX_WORLD_Y));
|
||||
}
|
||||
|
||||
float Basketball::congestion(U32FltVector2D pos, bool ignore, int whichPlayer) {
|
||||
float congestion = 0.0F;
|
||||
|
||||
for (int team = TEAM_HOME; team <= TEAM_AWAY; ++team) {
|
||||
Common::Array<CCollisionPlayer> *playerList = (team == TEAM_HOME) ? &_court->_homePlayerList : &_court->_awayPlayerList;
|
||||
|
||||
for (Common::Array<CCollisionPlayer>::iterator currentPlayer = playerList->begin(); currentPlayer != playerList->end(); ++currentPlayer) {
|
||||
if (currentPlayer->_playerIsInGame && (ignore && !(currentPlayer->_objectID == whichPlayer))) {
|
||||
float distance2 = pos.distance2(currentPlayer->center);
|
||||
|
||||
if (distance2 == 0.0F)
|
||||
return FLT_MAX;
|
||||
|
||||
congestion += (1 / distance2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return congestion;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userGetOpenSpot(int whichPlayer, U32FltVector2D upperLeft, U32FltVector2D lowerRight, U32FltVector2D passer, bool attract, U32FltVector2D attractPoint) {
|
||||
int xGranularity = 5;
|
||||
int yGranularity = 5;
|
||||
|
||||
int rectWidth = fabs(upperLeft.x - lowerRight.x);
|
||||
int rectHeight = fabs(upperLeft.y - lowerRight.y);
|
||||
|
||||
// Integer operation cast to float, this is intended!
|
||||
float xMesh = (float)(rectWidth / (xGranularity + 1));
|
||||
float yMesh = (float)(rectHeight / (yGranularity + 1));
|
||||
|
||||
float startX = upperLeft.x + xMesh / 2;
|
||||
float startY = upperLeft.y + yMesh / 2;
|
||||
|
||||
float x = startX, y = startY;
|
||||
|
||||
float bestCongestion = FLT_MAX;
|
||||
|
||||
U32FltVector2D bestPoint, point;
|
||||
|
||||
float tmp;
|
||||
|
||||
for (int ii = 0; ii < xGranularity; ii++) {
|
||||
for (int jj = 0; jj < yGranularity; jj++) {
|
||||
tmp = _vm->_basketball->congestion(point = U32FltVector2D(x, y), true, whichPlayer);
|
||||
|
||||
if (attract) {
|
||||
tmp -= (4 * (1 / point.distance2(attractPoint)));
|
||||
}
|
||||
|
||||
if (tmp < bestCongestion &&
|
||||
isPointInBounds(point)) {
|
||||
bestCongestion = tmp;
|
||||
bestPoint = point;
|
||||
}
|
||||
|
||||
y += yMesh;
|
||||
}
|
||||
|
||||
x += xMesh;
|
||||
y = startY;
|
||||
}
|
||||
|
||||
if (bestCongestion == FLT_MAX) {
|
||||
return 0;
|
||||
} else {
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, bestPoint.x);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, bestPoint.y);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int isPlayerInBounds(U32Sphere *player) {
|
||||
assert(player);
|
||||
|
||||
return (((player->center.x - player->radius) > -COLLISION_EPSILON) &&
|
||||
((player->center.x + player->radius) < (MAX_WORLD_X + COLLISION_EPSILON)) &&
|
||||
((player->center.y - player->radius) > -COLLISION_EPSILON) &&
|
||||
((player->center.y + player->radius) < (MAX_WORLD_Y + COLLISION_EPSILON)));
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userIsPlayerInBounds(int playerID) {
|
||||
U32Cylinder *player = _vm->_basketball->_court->getPlayerPtr(playerID);
|
||||
|
||||
int isPlayerInBoundsRes = isPlayerInBounds(player);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, isPlayerInBoundsRes);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userIsBallInBounds() {
|
||||
int isBallInBounds = isPlayerInBounds(&_vm->_basketball->_court->_basketBall);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, isBallInBounds);
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
175
engines/scumm/he/basketball/ai.h
Normal file
175
engines/scumm/he/basketball/ai.h
Normal file
@@ -0,0 +1,175 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_AI_H
|
||||
#define SCUMM_HE_BASKETBALL_AI_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/logic_he.h"
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define FLOAT_EPSILON 0.001F
|
||||
|
||||
inline int square(int x) { return x * x; }
|
||||
|
||||
class Line2D {
|
||||
public:
|
||||
Line2D(float x_coef, float y_coef, float constant) {
|
||||
_a = x_coef;
|
||||
_b = y_coef;
|
||||
_c = constant;
|
||||
}
|
||||
|
||||
Line2D(const U32FltVector2D &point1, const U32FltVector2D &point2) {
|
||||
LineFromTwoPoints(point1, point2);
|
||||
}
|
||||
|
||||
void LineFromTwoPoints(U32FltVector2D pt1, U32FltVector2D pt2) {
|
||||
float temp = (pt2.x - pt1.x);
|
||||
|
||||
if (fabs(temp) < FLOAT_EPSILON) {
|
||||
assert(((fabs(pt2.y - pt1.y) >= FLOAT_EPSILON)));
|
||||
_a = 1;
|
||||
_b = 0;
|
||||
} else {
|
||||
float m = (pt2.y - pt1.y) / temp;
|
||||
_a = -m;
|
||||
_b = 1;
|
||||
}
|
||||
|
||||
_c = -(_a * pt2.x + _b * pt2.y);
|
||||
}
|
||||
|
||||
inline float distance(U32FltVector2D point) {
|
||||
return fabs((_a * point.x + _b * point.y + _c) / sqrt(square(_a) + square(_b)));
|
||||
}
|
||||
|
||||
inline float distance2(U32FltVector2D point) {
|
||||
return fabs(square(_a * point.x + _b * point.y + _c) / (square(_a) + square(_b)));
|
||||
}
|
||||
|
||||
inline float angle() {
|
||||
return atan2(-_a, _b);
|
||||
}
|
||||
|
||||
bool inBetween(U32FltVector2D point, U32FltVector2D end1, U32FltVector2D end2) {
|
||||
assert((!onLine(end1) || !onLine(end2)));
|
||||
|
||||
point = projectPoint(point);
|
||||
float distance2 = end1.distance2(end2);
|
||||
|
||||
return (point.distance2(end1) <= distance2 && point.distance2(end2) <= distance2) ? true : false;
|
||||
}
|
||||
|
||||
bool onLine(U32FltVector2D point) {
|
||||
return (distance2(point) < 1.0F) ? true : false;
|
||||
}
|
||||
|
||||
U32FltVector2D projectPoint(U32FltVector2D point) {
|
||||
return intersection(perpendicular(point));
|
||||
}
|
||||
|
||||
float getY(float x) {
|
||||
if (_b != 0.0F)
|
||||
return (-_a * x - _c) / _b;
|
||||
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
float getX(float y) {
|
||||
if (_a != 0.0F)
|
||||
return (-_b * y - _c) / _a;
|
||||
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
U32FltVector2D intersection(Line2D line) {
|
||||
U32FltVector2D result(0.0F, 0.0F);
|
||||
|
||||
assert(!sameSlope(line));
|
||||
|
||||
if (_b == 0.0F) {
|
||||
result.x = -_c / _a;
|
||||
result.y = line.getY(result.x);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (line._b == 0.0F) {
|
||||
result.x = -line._c / line._a;
|
||||
result.y = getY(result.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
result.x = (_c * line._b - _b * line._c) / (line._a * _b - _a * line._b);
|
||||
result.y = getY(result.x);
|
||||
return result;
|
||||
}
|
||||
|
||||
Line2D perpendicular(U32FltVector2D point) {
|
||||
return Line2D(_b, -_a, _a * point.y - _b * point.x);
|
||||
}
|
||||
|
||||
Line2D shiftY(float val) {
|
||||
return Line2D(_a, _b, _c - val * _b);
|
||||
}
|
||||
|
||||
Line2D shiftX(float val) {
|
||||
return Line2D(_a, _b, _c - val * _a);
|
||||
}
|
||||
|
||||
// Returns whether the projection of point1 is closer to targPoint than the projection of point2
|
||||
bool isPointCloserToPointOnLine(U32FltVector2D point1, U32FltVector2D point2, U32FltVector2D targPoint) {
|
||||
|
||||
assert(!onLine(targPoint));
|
||||
|
||||
point1 = projectPoint(point1);
|
||||
point2 = projectPoint(point2);
|
||||
|
||||
return (point1.distance(targPoint) < point2.distance(targPoint)) ? true : false;
|
||||
}
|
||||
|
||||
bool halfPlaneTest(U32FltVector2D point) {
|
||||
if (_b == 0)
|
||||
return (point.x < -_c / _a) ? true : false;
|
||||
|
||||
return (point.y > getY(point.x)) ? true : false;
|
||||
}
|
||||
|
||||
bool sameSlope(Line2D line) {
|
||||
return ((_b == 0 && line._b == 0) || ((_a / _b) == (line._a / line._b))) ? true : false;
|
||||
}
|
||||
|
||||
private:
|
||||
float _a, _b, _c; // The three coeffs in the line equation:
|
||||
// Ax + By + C = 0
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_AI_H
|
||||
238
engines/scumm/he/basketball/basketball.cpp
Normal file
238
engines/scumm/he/basketball/basketball.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/basketball/basketball.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_shields.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
Basketball::Basketball(ScummEngine_v100he *vm) {
|
||||
_vm = vm;
|
||||
_court = new CBBallCourt();
|
||||
_shields = new CCollisionShieldVector();
|
||||
}
|
||||
|
||||
Basketball::~Basketball() {
|
||||
delete _court;
|
||||
delete _shields;
|
||||
}
|
||||
|
||||
int Basketball::u32FloatToInt(float input) {
|
||||
int output = 0;
|
||||
|
||||
if (input < 0)
|
||||
output = (int)(input - 0.5F);
|
||||
else if (input > 0)
|
||||
output = (int)(input + 0.5F);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
int Basketball::u32DoubleToInt(double input) {
|
||||
int output = 0;
|
||||
|
||||
if (input < 0)
|
||||
output = (int)(input - 0.5);
|
||||
else if (input > 0)
|
||||
output = (int)(input + 0.5);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void Basketball::fillBallTargetList(const CCollisionSphere *sourceObject, CCollisionObjectVector *targetList) {
|
||||
// Add all of the court objects...
|
||||
_court->_objectTree.selectObjectsInBound(sourceObject->getBigBoundingBox(), targetList);
|
||||
|
||||
// Add the shields...
|
||||
CCollisionShieldVector::const_iterator shieldIt;
|
||||
|
||||
for (shieldIt = _shields->begin(); shieldIt != _shields->end(); ++shieldIt) {
|
||||
if (!shieldIt->_ignore) {
|
||||
targetList->push_back(&(*shieldIt));
|
||||
}
|
||||
}
|
||||
|
||||
// Add all of the home players...
|
||||
Common::Array<CCollisionPlayer>::const_iterator homePlayerIt;
|
||||
|
||||
for (homePlayerIt = _court->_homePlayerList.begin();
|
||||
homePlayerIt != _court->_homePlayerList.end();
|
||||
++homePlayerIt) {
|
||||
if (!homePlayerIt->_ignore) {
|
||||
targetList->push_back(&(*homePlayerIt));
|
||||
}
|
||||
}
|
||||
|
||||
// Add all of the away players...
|
||||
Common::Array<CCollisionPlayer>::const_iterator awayPlayerIt;
|
||||
|
||||
for (awayPlayerIt = _court->_awayPlayerList.begin();
|
||||
awayPlayerIt != _court->_awayPlayerList.end();
|
||||
++awayPlayerIt) {
|
||||
if (!awayPlayerIt->_ignore) {
|
||||
targetList->push_back(&(*awayPlayerIt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Basketball::fillPlayerTargetList(const CCollisionPlayer *sourceObject, CCollisionObjectVector *targetList) {
|
||||
// Add all of the court objects...
|
||||
_court->_objectTree.selectObjectsInBound(sourceObject->getBigBoundingBox(), targetList);
|
||||
|
||||
// Add the shields if the player has the ball...
|
||||
if (sourceObject->_playerHasBall) {
|
||||
CCollisionShieldVector::const_iterator shieldIt;
|
||||
|
||||
for (shieldIt = _shields->begin(); shieldIt != _shields->end(); ++shieldIt) {
|
||||
if (!shieldIt->_ignore) {
|
||||
targetList->push_back(&(*shieldIt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the basketball...
|
||||
if (!_court->_basketBall._ignore) {
|
||||
targetList->push_back((ICollisionObject *)&_court->_basketBall);
|
||||
}
|
||||
|
||||
// Add the virtual basketball...
|
||||
if (!_court->_virtualBall._ignore) {
|
||||
targetList->push_back((ICollisionObject *)&_court->_virtualBall);
|
||||
}
|
||||
|
||||
// Add all of the home players...
|
||||
Common::Array<CCollisionPlayer>::const_iterator homePlayerIt;
|
||||
|
||||
for (homePlayerIt = _court->_homePlayerList.begin();
|
||||
homePlayerIt != _court->_homePlayerList.end();
|
||||
++homePlayerIt) {
|
||||
if ((sourceObject != &(*homePlayerIt)) &&
|
||||
(!homePlayerIt->_ignore)) {
|
||||
targetList->push_back(&(*homePlayerIt));
|
||||
}
|
||||
}
|
||||
|
||||
// Add all of the away players...
|
||||
Common::Array<CCollisionPlayer>::const_iterator awayPlayerIt;
|
||||
|
||||
for (awayPlayerIt = _court->_awayPlayerList.begin();
|
||||
awayPlayerIt != _court->_awayPlayerList.end();
|
||||
++awayPlayerIt) {
|
||||
if ((sourceObject != &(*awayPlayerIt)) &&
|
||||
(!awayPlayerIt->_ignore)) {
|
||||
targetList->push_back(&(*awayPlayerIt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double Basketball::getLaunchAngle(int velocity, int hDist, int vDist, int gravity) {
|
||||
double theta;
|
||||
double bestTheta;
|
||||
double tempTheta;
|
||||
double thetaMin, thetaMax;
|
||||
|
||||
double answer;
|
||||
double bestAnswer;
|
||||
double hiAnswer, loAnswer;
|
||||
|
||||
double time;
|
||||
double bestTime;
|
||||
|
||||
double targetAngle;
|
||||
int counter;
|
||||
|
||||
assert(hDist > 0);
|
||||
|
||||
// Set the search limits, and get a first guess...
|
||||
targetAngle = atan2(vDist, hDist);
|
||||
|
||||
// The minimum angle of the pass is the angle directly between us and the target...
|
||||
thetaMin = targetAngle;
|
||||
|
||||
// The maximum angle is straight up...
|
||||
thetaMax = BBALL_M_PI / 4;
|
||||
|
||||
theta = (thetaMin + thetaMax) / 2;
|
||||
bestTheta = theta;
|
||||
bestTime = hDist / (velocity * cos(theta));
|
||||
if (bestTime < 0)
|
||||
bestTime *= -1;
|
||||
|
||||
// Start binary searching for a close answer...
|
||||
counter = 0;
|
||||
answer = (2 * velocity * velocity * hDist * sin(theta) * cos(theta)) - (2 * velocity * velocity * vDist * cos(theta) * cos(theta)) - (gravity * hDist * hDist);
|
||||
if (answer < 0)
|
||||
answer *= -1;
|
||||
bestAnswer = answer;
|
||||
|
||||
while ((fabs(answer * 1000.0) > 10.0) && (++counter <= 100)) {
|
||||
if (theta < 0)
|
||||
targetAngle += (2 * BBALL_M_PI);
|
||||
|
||||
// Get a theta above and below the current one and see which one gets us closer
|
||||
// to satisfying the equation...
|
||||
tempTheta = (thetaMin + theta) / 2;
|
||||
loAnswer = (2 * velocity * velocity * hDist * sin(tempTheta) * cos(tempTheta)) - (2 * velocity * velocity * vDist * cos(tempTheta) * cos(tempTheta)) - (gravity * hDist * hDist);
|
||||
if (loAnswer < 0)
|
||||
loAnswer = 0 - loAnswer;
|
||||
|
||||
tempTheta = (thetaMax + theta) / 2;
|
||||
hiAnswer = (2 * velocity * velocity * hDist * sin(tempTheta) * cos(tempTheta)) - (2 * velocity * velocity * vDist * cos(tempTheta) * cos(tempTheta)) - (gravity * hDist * hDist);
|
||||
if (hiAnswer < 0)
|
||||
hiAnswer = 0 - hiAnswer;
|
||||
|
||||
if (loAnswer < hiAnswer) {
|
||||
thetaMax = theta;
|
||||
answer = loAnswer;
|
||||
} else {
|
||||
thetaMin = theta;
|
||||
answer = hiAnswer;
|
||||
}
|
||||
theta = (thetaMin + thetaMax) / 2;
|
||||
if (answer < 0)
|
||||
answer *= -1;
|
||||
|
||||
if (answer <= bestAnswer) {
|
||||
if (answer == bestAnswer) {
|
||||
time = hDist / (velocity * cos(theta));
|
||||
if (time < 0)
|
||||
time *= -1;
|
||||
if (time < bestTime) {
|
||||
bestTheta = theta;
|
||||
bestTime = time;
|
||||
bestAnswer = answer;
|
||||
}
|
||||
} else {
|
||||
bestTheta = theta;
|
||||
bestTime = hDist / (velocity * cos(theta));
|
||||
if (bestTime < 0)
|
||||
bestTime *= -1;
|
||||
bestAnswer = answer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bestTheta = (bestTheta * 180) / BBALL_M_PI;
|
||||
return bestTheta;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
87
engines/scumm/he/basketball/basketball.h
Normal file
87
engines/scumm/he/basketball/basketball.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_BASKETBALL_H
|
||||
#define SCUMM_HE_BASKETBALL_BASKETBALL_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/logic_he.h"
|
||||
#include "scumm/he/basketball/court.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_player.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_shields.h"
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/stack.h"
|
||||
#include "common/queue.h"
|
||||
#include "common/std/set.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
class LogicHEBasketball;
|
||||
|
||||
class Basketball {
|
||||
|
||||
public:
|
||||
Basketball(ScummEngine_v100he *vm);
|
||||
~Basketball();
|
||||
|
||||
int u32FloatToInt(float input);
|
||||
int u32DoubleToInt(double input);
|
||||
|
||||
int numOpponentsInCone(int team, float widthDistanceRatio, const U32FltVector2D &end, const U32FltVector2D &focus);
|
||||
float congestion(U32FltVector2D pos, bool ignore, int whichPlayer);
|
||||
void fillPlayerTargetList(const CCollisionPlayer *sourceObject, CCollisionObjectVector *targetList);
|
||||
void fillBallTargetList(const CCollisionSphere *sourceObject, CCollisionObjectVector *targetList);
|
||||
double getLaunchAngle(int velocity, int hDist, int vDist, int gravity);
|
||||
float getAvoidanceDistance(const U32Circle &playerMarker, const CCollisionPlayer &obstacle);
|
||||
CCollisionPlayer *detectObstacle(const U32Circle &playerMarker, int playerID, const U32FltPoint2D &targetLocation, bool targetIsObstacle, U32FltPoint2D *intersection, CBBallCourt *court);
|
||||
bool avoidObstacle(const U32Circle &playerMarker, const U32FltPoint2D &targetLocation, const CCollisionPlayer &obstacle, ERevDirection whichDirection, U32FltPoint2D *newTarget);
|
||||
ERevDirection getAvoidanceDirection(const U32Circle &playerMarker, const U32FltPoint2D &targetLocation, const CCollisionPlayer &obstacle);
|
||||
bool getPathDistance(U32Circle *playerMarker, int playerID, Common::Stack<U32FltPoint2D> *targetStack, ERevDirection lastTurn, float *pathDistance, Common::Queue<U32FltPoint2D> *wayPointQueue, Std::set<int> *obstacleSet, CBBallCourt *court);
|
||||
|
||||
void pushTargetOutOfObstacle(const U32Circle &playerMarker,
|
||||
const CCollisionPlayer &obstacle,
|
||||
Common::Stack<U32FltPoint2D> *targetStack);
|
||||
|
||||
ERevDirection getBestPath(const U32Circle &playerMarker,
|
||||
int playerID,
|
||||
Common::Stack<U32FltPoint2D> *targetStack,
|
||||
CCollisionPlayer *obstacle,
|
||||
ERevDirection lastTurn,
|
||||
float *distance,
|
||||
Common::Queue<U32FltPoint2D> *wayPointQueue,
|
||||
Std::set<int> *obstacleSet,
|
||||
CBBallCourt *court);
|
||||
|
||||
CBBallCourt *_court;
|
||||
CCollisionShieldVector *_shields;
|
||||
|
||||
private:
|
||||
ScummEngine_v100he *_vm;
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_BASKETBALL_H
|
||||
568
engines/scumm/he/basketball/collision/bball_collision.cpp
Normal file
568
engines/scumm/he/basketball/collision/bball_collision.cpp
Normal file
@@ -0,0 +1,568 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/basketball/basketball.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision.h"
|
||||
#include "scumm/he/basketball/geo_translations.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
int LogicHEBasketball::u32_userInitCourt(int courtID) {
|
||||
static const char *courtNames[] = {
|
||||
"",
|
||||
"Dobbaguchi", "Jocindas", "SandyFlats", "Queens",
|
||||
"Park", "Scheffler", "Polk", "McMillan",
|
||||
"CrownHill", "Memorial", "TechState", "Garden",
|
||||
"Moon", "Barn"
|
||||
};
|
||||
|
||||
|
||||
// Make sure nothing on the court is currently initialized.
|
||||
_vm->_basketball->_court->_objectTree.~CCollisionObjectTree();
|
||||
_vm->_basketball->_court->_objectList.clear();
|
||||
_vm->_basketball->_court->_homePlayerList.clear();
|
||||
_vm->_basketball->_court->_awayPlayerList.clear();
|
||||
|
||||
// Initialize the shot spots
|
||||
_vm->_basketball->_court->_shotSpot[LEFT_BASKET].center.x = BASKET_X;
|
||||
_vm->_basketball->_court->_shotSpot[LEFT_BASKET].center.y = BASKET_Y;
|
||||
_vm->_basketball->_court->_shotSpot[LEFT_BASKET].center.z = BASKET_Z;
|
||||
_vm->_basketball->_court->_shotSpot[LEFT_BASKET].radius = SHOT_SPOT_RADIUS;
|
||||
|
||||
_vm->_basketball->_court->_shotSpot[RIGHT_BASKET].center.x = MAX_WORLD_X - BASKET_X;
|
||||
_vm->_basketball->_court->_shotSpot[RIGHT_BASKET].center.y = BASKET_Y;
|
||||
_vm->_basketball->_court->_shotSpot[RIGHT_BASKET].center.z = BASKET_Z;
|
||||
_vm->_basketball->_court->_shotSpot[RIGHT_BASKET].radius = SHOT_SPOT_RADIUS;
|
||||
|
||||
// Get the name and object file for this court.
|
||||
_vm->_basketball->_court->_name = Common::String(courtNames[courtID]);
|
||||
|
||||
// Put together to relative path and filename.
|
||||
Common::Path objectFileName = Common::Path(Common::String::format("data/courts/%s.cof", courtNames[courtID]));
|
||||
|
||||
// Create a file stream to the collision object file
|
||||
Common::File objectFile;
|
||||
if (!objectFile.open(objectFileName))
|
||||
error("LogicHEBasketball::u32_userInitCourt(): Could not open file '%s'", objectFileName.toString(Common::Path::kNativeSeparator).c_str());
|
||||
|
||||
// Read in the object file version
|
||||
char fileVersion[32];
|
||||
int versionStringLength = objectFile.readUint32LE();
|
||||
|
||||
if (versionStringLength <= 0 || versionStringLength > ARRAYSIZE(fileVersion) - 1)
|
||||
error("LogicHEBasketball::u32_userInitCourt(): Read from stream did not read the version string length correctly.");
|
||||
|
||||
objectFile.read(fileVersion, versionStringLength);
|
||||
fileVersion[versionStringLength] = '\0';
|
||||
|
||||
if (strcmp(fileVersion, "01.05"))
|
||||
error("LogicHEBasketball::u32_userInitCourt(): Invalid court version field: %s", fileVersion);
|
||||
|
||||
// Read in the total number of objects
|
||||
_vm->_basketball->_court->_objectCount = objectFile.readUint32LE();
|
||||
_vm->_basketball->_court->_objectList.resize(_vm->_basketball->_court->_objectCount);
|
||||
|
||||
// Keep a list of pointers to the court objects...
|
||||
CCollisionObjectVector objectPtrList;
|
||||
objectPtrList.resize(_vm->_basketball->_court->_objectCount);
|
||||
|
||||
// Read in each court object...
|
||||
for (int i = 0; i < _vm->_basketball->_court->_objectCount; i++) {
|
||||
CCollisionBox *currentObject = &_vm->_basketball->_court->_objectList[i];
|
||||
|
||||
// Read in this object's description...
|
||||
int descriptionStringLength = objectFile.readUint32LE();
|
||||
char *tmp = (char *)malloc(descriptionStringLength + 1);
|
||||
|
||||
assert(tmp);
|
||||
|
||||
objectFile.read(tmp, descriptionStringLength);
|
||||
tmp[descriptionStringLength] = '\0';
|
||||
|
||||
Common::String tmp2(tmp);
|
||||
|
||||
_vm->_basketball->_court->_objectList[i]._description = Common::move(tmp2);
|
||||
|
||||
free(tmp);
|
||||
|
||||
// Read in all other object attributes...
|
||||
currentObject->_objectType = (EObjectType)objectFile.readUint32LE();
|
||||
currentObject->_collisionEfficiency = objectFile.readFloatLE();
|
||||
currentObject->_friction = objectFile.readFloatLE();
|
||||
currentObject->_soundNumber = objectFile.readUint32LE();
|
||||
currentObject->_objectID = objectFile.readUint32LE();
|
||||
currentObject->minPoint.x = objectFile.readUint32LE();
|
||||
currentObject->minPoint.y = objectFile.readUint32LE();
|
||||
currentObject->minPoint.z = objectFile.readUint32LE();
|
||||
currentObject->maxPoint.x = objectFile.readUint32LE();
|
||||
currentObject->maxPoint.y = objectFile.readUint32LE();
|
||||
currentObject->maxPoint.z = objectFile.readUint32LE();
|
||||
objectPtrList[i] = currentObject;
|
||||
|
||||
// Decide if this is a backboard, and keep track of it if it is...
|
||||
if (currentObject->_objectType == kBackboard) {
|
||||
// See which backboard it is...
|
||||
if (((currentObject->minPoint.x + currentObject->maxPoint.x) / 2) < (MAX_WORLD_X / 2)) {
|
||||
_vm->_basketball->_court->_backboardIndex[LEFT_BASKET] = i;
|
||||
} else {
|
||||
_vm->_basketball->_court->_backboardIndex[RIGHT_BASKET] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_vm->_basketball->_court->_objectTree.initialize(objectPtrList);
|
||||
|
||||
|
||||
// Lower all the shields...
|
||||
u32_userLowerShields(ALL_SHIELD_ID);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userDeinitCourt() {
|
||||
// Make sure the collision object tree has been cleared...
|
||||
_vm->_basketball->_court->_objectTree.~CCollisionObjectTree();
|
||||
|
||||
// Lower all the shields...
|
||||
u32_userLowerShields(ALL_SHIELD_ID);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userInitBall(U32FltPoint3D &ballLocation, U32FltVector3D &bellVelocity, int radius, int ballID) {
|
||||
_vm->_basketball->_court->_basketBall._description = "Basketball";
|
||||
_vm->_basketball->_court->_basketBall._objectType = kBall;
|
||||
_vm->_basketball->_court->_basketBall._objectID = ballID;
|
||||
_vm->_basketball->_court->_basketBall.center = ballLocation;
|
||||
_vm->_basketball->_court->_basketBall._velocity = bellVelocity;
|
||||
_vm->_basketball->_court->_basketBall.radius = radius;
|
||||
_vm->_basketball->_court->_basketBall._collisionEfficiency = 1.0F;
|
||||
_vm->_basketball->_court->_basketBall._friction = 0.0F;
|
||||
_vm->_basketball->_court->_basketBall._ignore = false;
|
||||
|
||||
_vm->_basketball->_court->_basketBall.save();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userInitVirtualBall(U32FltPoint3D &ballLocation, U32FltVector3D &bellVelocity, int radius, int ballID) {
|
||||
_vm->_basketball->_court->_virtualBall._description = "Virtual Basketball";
|
||||
_vm->_basketball->_court->_virtualBall._objectType = kBall;
|
||||
_vm->_basketball->_court->_virtualBall._objectID = ballID;
|
||||
_vm->_basketball->_court->_virtualBall.center = ballLocation;
|
||||
_vm->_basketball->_court->_virtualBall._velocity = bellVelocity;
|
||||
_vm->_basketball->_court->_virtualBall.radius = radius;
|
||||
_vm->_basketball->_court->_virtualBall._collisionEfficiency = 1.0F;
|
||||
_vm->_basketball->_court->_virtualBall._friction = 0.0F;
|
||||
_vm->_basketball->_court->_virtualBall._ignore = false;
|
||||
|
||||
_vm->_basketball->_court->_virtualBall.save();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userDeinitBall() {
|
||||
_vm->_basketball->_court->_basketBall._ignore = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userDeinitVirtualBall() {
|
||||
_vm->_basketball->_court->_virtualBall._ignore = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userInitPlayer(int playerID, U32FltPoint3D &playerLocation, int height, int radius, bool playerIsInGame) {
|
||||
if (!((FIRST_PLAYER <= playerID) && (playerID <= LAST_PLAYER)))
|
||||
error("LogicHEBasketball::u32_userInitPlayer(): Passed in invalid player ID");
|
||||
|
||||
// Cycle through all of the player slots until an empty one is found...
|
||||
Common::Array<CCollisionPlayer> *playerList = _vm->_basketball->_court->getPlayerListPtr(playerID);
|
||||
if (playerList->size() < MAX_PLAYERS_ON_TEAM) {
|
||||
CCollisionPlayer newPlayer;
|
||||
newPlayer._objectType = kPlayer;
|
||||
newPlayer._objectID = playerID;
|
||||
newPlayer.height = height;
|
||||
newPlayer._catchHeight = PLAYER_CATCH_HEIGHT;
|
||||
newPlayer.radius = radius;
|
||||
newPlayer.center = playerLocation;
|
||||
newPlayer.center.z = playerLocation.z + (height / 2);
|
||||
newPlayer._collisionEfficiency = 0.5F;
|
||||
newPlayer._friction = 0.5F;
|
||||
newPlayer._playerIsInGame = playerIsInGame;
|
||||
newPlayer.save();
|
||||
playerList->push_back(newPlayer);
|
||||
return 1;
|
||||
} else {
|
||||
warning("LogicHEBasketball::u32_userInitPlayer(): There were no empty player slots. You can't initialize a new player until you deinit one.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userDeinitPlayer(int playerID) {
|
||||
if (!((FIRST_PLAYER <= playerID) && (playerID <= LAST_PLAYER)))
|
||||
error("LogicHEBasketball::u32_userDeinitPlayer(): Passed in invalid player ID");
|
||||
|
||||
int index = _vm->_basketball->_court->getPlayerIndex(playerID);
|
||||
Common::Array<CCollisionPlayer> *playerList = _vm->_basketball->_court->getPlayerListPtr(playerID);
|
||||
playerList->remove_at(index);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userPlayerOff(int playerID) {
|
||||
if (!((FIRST_PLAYER <= playerID) && (playerID <= LAST_PLAYER)))
|
||||
error("LogicHEBasketball::u32_userPlayerOff(): Passed in invalid player ID");
|
||||
|
||||
_vm->_basketball->_court->getPlayerPtr(playerID)->_ignore = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userPlayerOn(int playerID) {
|
||||
if (!((FIRST_PLAYER <= playerID) && (playerID <= LAST_PLAYER)))
|
||||
error("LogicHEBasketball::u32_userPlayerOn(): Passed in invalid player ID");
|
||||
|
||||
_vm->_basketball->_court->getPlayerPtr(playerID)->_ignore = false;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void trackCollisionObject(const ICollisionObject &sourceObject, const ICollisionObject &targetObject, CCollisionObjectVector *objectVector) {
|
||||
float currentDist = sourceObject.getObjectDistance(targetObject);
|
||||
|
||||
// As an object moves backwards along its velocity vector and new collisions
|
||||
// are detected, older collisions may become invalid. Here, we go through prior
|
||||
// collisions, and see which ones are invalidated by this new collision.
|
||||
for (CCollisionObjectVector::const_iterator objectIt = objectVector->begin();
|
||||
objectIt != objectVector->end();
|
||||
++objectIt) {
|
||||
float pastDist = sourceObject.getObjectDistance(**objectIt);
|
||||
|
||||
// If the distance between the source object and the current target object
|
||||
// is less than or equal to the distance between the source object and the last
|
||||
// target object, then the current target object is stored along side the last
|
||||
// target object. Otherwise, the current object replaces the last object.
|
||||
if ((fabs(pastDist - currentDist) < COLLISION_EPSILON) ||
|
||||
(!sourceObject.isCollisionHandled(targetObject)) ||
|
||||
(!sourceObject.isCollisionHandled(**objectIt))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that we aren't keeping track of the same object twice...
|
||||
if (!objectVector->contains(targetObject)) {
|
||||
objectVector->push_back(&targetObject);
|
||||
}
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userDetectBallCollision(U32FltPoint3D &ballLocation, U32FltVector3D &ballVector, int recordCollision, int ballID) {
|
||||
bool ballIsClear = false; // Flag that indicates if the ball collided with any objects on its current vector
|
||||
bool errorOccurred = false;
|
||||
|
||||
U32Distance3D distance; // The distance between the ball and a collision object candidate
|
||||
CCollisionObjectVector targetList; // All potential collision candidates
|
||||
CCollisionObjectVector collisionVector; // All objects that have been collided with
|
||||
CCollisionObjectVector rollingVector; // All objects that have been rolled on
|
||||
|
||||
int collisionOccurred = 0;
|
||||
int rollingHappened = 0;
|
||||
|
||||
// Determine which ball we're dealing with...
|
||||
CCollisionBasketball *sourceBall = _vm->_basketball->_court->getBallPtr(ballID);
|
||||
|
||||
// Update the position and vector of the basketball...
|
||||
sourceBall->center = ballLocation;
|
||||
sourceBall->_velocity = ballVector;
|
||||
|
||||
// Clear the ball's collision stack...
|
||||
sourceBall->_objectCollisionHistory.clear();
|
||||
sourceBall->_objectRollingHistory.clear();
|
||||
|
||||
// Find out who our potential collision candidates are...
|
||||
_vm->_basketball->fillBallTargetList(sourceBall, &targetList);
|
||||
|
||||
// See if there was an error while traversing the object tree,
|
||||
// if there was put the player in the last known safe position...
|
||||
if (_vm->_basketball->_court->_objectTree.checkErrors()) {
|
||||
sourceBall->restore();
|
||||
}
|
||||
|
||||
for (int i = 0; (i < MAX_BALL_COLLISION_PASSES) && (!ballIsClear); i++) {
|
||||
float totalTime = 0.0F; // The time it takes to back out of all objects we have intersected while on the current vector
|
||||
ballIsClear = true;
|
||||
|
||||
// Go through all of the collision candidates....
|
||||
for (size_t j = 0; j < targetList.size(); ++j) {
|
||||
const ICollisionObject *targetObject = targetList[j];
|
||||
assert(targetObject);
|
||||
|
||||
// See if we intersect the current object...
|
||||
bool intersectionResult = sourceBall->testObjectIntersection(*targetObject, &distance);
|
||||
if (intersectionResult) {
|
||||
// If we are intersecting a moving object, make sure that we actually
|
||||
// ran into them, and they didn't just run into us...
|
||||
if (sourceBall->validateCollision(*targetObject, &distance)) {
|
||||
// If we are intersecting the object, back out of it...
|
||||
if (sourceBall->backOutOfObject(*targetObject, &distance, &totalTime)) {
|
||||
// Move in to the exact point of collision...
|
||||
if (sourceBall->nudgeObject(*targetObject, &distance, &totalTime)) {
|
||||
// Keep track of this object so we can respond to the collision later...
|
||||
trackCollisionObject(*sourceBall, *targetObject, &sourceBall->_objectCollisionHistory);
|
||||
|
||||
if (sourceBall->isCollisionHandled(*targetObject)) {
|
||||
trackCollisionObject(*sourceBall, *targetObject, &collisionVector);
|
||||
ballIsClear = false;
|
||||
}
|
||||
|
||||
collisionOccurred = 1;
|
||||
} else {
|
||||
errorOccurred = true;
|
||||
}
|
||||
} else {
|
||||
errorOccurred = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// See if we are passing over a player...
|
||||
if (sourceBall->testCatch(*targetObject, &distance, _vm->_basketball->_court)) {
|
||||
trackCollisionObject(*sourceBall, *targetObject, &sourceBall->_objectCollisionHistory);
|
||||
collisionOccurred = true;
|
||||
}
|
||||
}
|
||||
|
||||
// See if we are rolling on the current object...
|
||||
if (sourceBall->isOnObject(*targetObject, distance)) {
|
||||
rollingHappened = 1;
|
||||
|
||||
if (!intersectionResult) {
|
||||
// This is not really a collision, but the ball is rolling, so we want to slow it down...
|
||||
trackCollisionObject(*sourceBall, *targetObject, &rollingVector);
|
||||
trackCollisionObject(*sourceBall, *targetObject, &sourceBall->_objectRollingHistory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust the ball's velocity and position due to any collisions...
|
||||
sourceBall->handleCollisions(&rollingVector, &totalTime, false);
|
||||
sourceBall->handleCollisions(&collisionVector, &totalTime, true);
|
||||
}
|
||||
|
||||
// Keep track of how long we've been rolling...
|
||||
if (rollingHappened) {
|
||||
++sourceBall->_rollingCount;
|
||||
} else {
|
||||
sourceBall->_rollingCount = 0;
|
||||
}
|
||||
|
||||
// If there were no errors this frame, save the position...
|
||||
if (!errorOccurred) {
|
||||
sourceBall->save();
|
||||
}
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(sourceBall->center.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(sourceBall->center.y));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_C, _vm->_basketball->u32FloatToInt(sourceBall->center.z));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_D, _vm->_basketball->u32FloatToInt(sourceBall->_velocity.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_E, _vm->_basketball->u32FloatToInt(sourceBall->_velocity.y));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_F, _vm->_basketball->u32FloatToInt(sourceBall->_velocity.z));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_G, collisionOccurred);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_H, rollingHappened != 0 ? 0 : 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userDetectPlayerCollision(int playerID, U32FltPoint3D &playerLocation, U32FltVector3D &playerVector, bool playerHasBall) {
|
||||
U32Distance3D distance; // The distance between the ball and a collision object candidate
|
||||
CCollisionObjectVector collisionVector; // All objects that have been collided with
|
||||
|
||||
int playerIsOnObject = 0;
|
||||
int collisionOccurred = 0;
|
||||
|
||||
bool playerIsClear = false;
|
||||
bool errorOccurred = false;
|
||||
|
||||
float totalTime = 0.0F; // The time it takes to back out of all objects we have intersected on this frame
|
||||
|
||||
if (!((FIRST_PLAYER <= playerID) && (playerID <= LAST_PLAYER)))
|
||||
error("LogicHEBasketball::u32_userDetectPlayerCollision(): Passed in invalid player ID");
|
||||
|
||||
// Get the player who is being tested...
|
||||
CCollisionPlayer *sourcePlayer = _vm->_basketball->_court->getPlayerPtr(playerID);
|
||||
|
||||
// Update the player's status...
|
||||
sourcePlayer->_playerHasBall = playerHasBall;
|
||||
|
||||
// In SCUMM code, the center of a player in the z dimension is at their feet.
|
||||
// In U32 code, it is in the middle of the cylinder, so make the translation...
|
||||
playerLocation.z += (sourcePlayer->height / 2);
|
||||
|
||||
// Update the player's position and velocity...
|
||||
sourcePlayer->center = playerLocation;
|
||||
sourcePlayer->_velocity = playerVector;
|
||||
sourcePlayer->_movementType = kStraight;
|
||||
|
||||
// Clear the player's collision stack...
|
||||
sourcePlayer->_objectCollisionHistory.clear();
|
||||
sourcePlayer->_objectRollingHistory.clear();
|
||||
|
||||
// Find out who our potential collision candidates are...
|
||||
CCollisionObjectVector targetList;
|
||||
_vm->_basketball->fillPlayerTargetList(sourcePlayer, &targetList);
|
||||
|
||||
// See if there was an error while traversing the object tree,
|
||||
// if there was put the player in the last known safe position...
|
||||
if (_vm->_basketball->_court->_objectTree.checkErrors()) {
|
||||
sourcePlayer->restore();
|
||||
}
|
||||
|
||||
for (int i = 0; (i < MAX_PLAYER_COLLISION_PASSES) && (!playerIsClear); i++) {
|
||||
playerIsClear = 1;
|
||||
|
||||
// Check all of the collision candidates...
|
||||
for (size_t j = 0; j < targetList.size(); ++j) {
|
||||
const ICollisionObject *targetObject = targetList[j];
|
||||
assert(targetObject);
|
||||
|
||||
// See if we intersect the current object...
|
||||
bool intersectionResult = sourcePlayer->testObjectIntersection(*targetObject, &distance);
|
||||
if (intersectionResult) {
|
||||
// If we are intersecting a moving object, make sure that we actually
|
||||
// ran into them, and they didn't just run into us...
|
||||
if (sourcePlayer->validateCollision(*targetObject, &distance)) {
|
||||
// If we are intersecting an object, back out to the exact point of collision...
|
||||
if (sourcePlayer->backOutOfObject(*targetObject, &distance, &totalTime)) {
|
||||
// Move in to the exact point of collision...
|
||||
if (sourcePlayer->nudgeObject(*targetObject, &distance, &totalTime)) {
|
||||
trackCollisionObject(*sourcePlayer, *targetObject, &sourcePlayer->_objectCollisionHistory);
|
||||
collisionOccurred = true;
|
||||
|
||||
if (sourcePlayer->isCollisionHandled(*targetObject)) {
|
||||
trackCollisionObject(*sourcePlayer, *targetObject, &collisionVector);
|
||||
playerIsClear = false;
|
||||
}
|
||||
} else {
|
||||
errorOccurred = true;
|
||||
}
|
||||
} else {
|
||||
errorOccurred = true;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// See if the virtual ball is passing over us...
|
||||
if (sourcePlayer->testCatch(*targetObject, &distance, _vm->_basketball->_court)) {
|
||||
trackCollisionObject(*sourcePlayer, *targetObject, &sourcePlayer->_objectCollisionHistory);
|
||||
collisionOccurred = true;
|
||||
}
|
||||
}
|
||||
|
||||
// See if we are standing on the current object...
|
||||
if (sourcePlayer->isOnObject(*targetObject, distance)) {
|
||||
playerIsOnObject = true;
|
||||
}
|
||||
}
|
||||
|
||||
sourcePlayer->handleCollisions(&collisionVector, &totalTime, true);
|
||||
}
|
||||
|
||||
// If there were no errors this frame, save the position...
|
||||
if (!errorOccurred) {
|
||||
sourcePlayer->save();
|
||||
}
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(sourcePlayer->center.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(sourcePlayer->center.y));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_C, _vm->_basketball->u32FloatToInt(sourcePlayer->center.z - (sourcePlayer->height / 2)));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_D, _vm->_basketball->u32FloatToInt(sourcePlayer->_velocity.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_E, _vm->_basketball->u32FloatToInt(sourcePlayer->_velocity.y));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_F, _vm->_basketball->u32FloatToInt(sourcePlayer->_velocity.z));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_G, collisionOccurred);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_H, playerIsOnObject != 0 ? 0 : 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userGetLastBallCollision(int ballID) {
|
||||
EObjectType lastObjectType = kNoObjectType;
|
||||
int objectID = 0;
|
||||
|
||||
// Determine which ball we're dealing with
|
||||
CCollisionSphere *sourceBall;
|
||||
if (ballID == _vm->_basketball->_court->_basketBall._objectID) {
|
||||
sourceBall = (CCollisionSphere *)&_vm->_basketball->_court->_basketBall;
|
||||
} else if (ballID == _vm->_basketball->_court->_virtualBall._objectID) {
|
||||
sourceBall = (CCollisionSphere *)&_vm->_basketball->_court->_virtualBall;
|
||||
} else {
|
||||
warning("LogicHEBasketball::u32_userGetLastBallCollision(): Invalid ball ID %d.", ballID);
|
||||
sourceBall = (CCollisionSphere *)&_vm->_basketball->_court->_basketBall;
|
||||
}
|
||||
|
||||
if (!sourceBall->_objectCollisionHistory.empty()) {
|
||||
lastObjectType = sourceBall->_objectCollisionHistory.back()->_objectType;
|
||||
objectID = sourceBall->_objectCollisionHistory.back()->_objectID;
|
||||
sourceBall->_objectCollisionHistory.pop_back();
|
||||
} else if (!sourceBall->_objectRollingHistory.empty()) {
|
||||
lastObjectType = sourceBall->_objectRollingHistory.back()->_objectType;
|
||||
objectID = sourceBall->_objectRollingHistory.back()->_objectID;
|
||||
sourceBall->_objectRollingHistory.pop_back();
|
||||
}
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, lastObjectType);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, objectID);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userGetLastPlayerCollision(int playerID) {
|
||||
EObjectType lastObjectType = kNoObjectType;
|
||||
int objectID = 0;
|
||||
bool playerIsOnObject = false;
|
||||
|
||||
CCollisionPlayer *pPlayer = _vm->_basketball->_court->getPlayerPtr(playerID);
|
||||
|
||||
if (!pPlayer->_objectCollisionHistory.empty()) {
|
||||
const ICollisionObject *targetObject = pPlayer->_objectCollisionHistory.back();
|
||||
|
||||
lastObjectType = targetObject->_objectType;
|
||||
objectID = targetObject->_objectID;
|
||||
|
||||
// See if we are standing on the current object
|
||||
U32Distance3D distance;
|
||||
pPlayer->testObjectIntersection(*targetObject, &distance);
|
||||
if (pPlayer->isOnObject(*targetObject, distance)) {
|
||||
playerIsOnObject = true;
|
||||
}
|
||||
|
||||
pPlayer->_objectCollisionHistory.pop_back();
|
||||
}
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, lastObjectType);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, objectID);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_C, playerIsOnObject);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
48
engines/scumm/he/basketball/collision/bball_collision.h
Normal file
48
engines/scumm/he/basketball/collision/bball_collision.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_H
|
||||
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define RIM_CE 0.4F
|
||||
#define BACKBOARD_CE 0.3F
|
||||
#define FLOOR_CE 0.65F
|
||||
|
||||
#define LEFT_BASKET 0
|
||||
#define RIGHT_BASKET 1
|
||||
|
||||
#define RIM_WIDTH (WORLD_UNIT_MULTIPLIER / 11)
|
||||
#define RIM_RADIUS ((3 * WORLD_UNIT_MULTIPLIER) / 4)
|
||||
|
||||
#define MAX_BALL_COLLISION_PASSES 10
|
||||
#define MAX_PLAYER_COLLISION_PASSES 3
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_H
|
||||
@@ -0,0 +1,45 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/basketball/court.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_basketball.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_box.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_node.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_tree.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
bool CCollisionBasketball::testCatch(const ICollisionObject &targetObject, U32Distance3D *distance, CBBallCourt *court) {
|
||||
if (targetObject._objectType == kPlayer) {
|
||||
ICollisionObject *object = const_cast<ICollisionObject *>(&targetObject);
|
||||
CCollisionPlayer *player = static_cast<CCollisionPlayer *>(object);
|
||||
return (player->testCatch(*this, distance, court));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
@@ -0,0 +1,47 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_BASKETBALL_H
|
||||
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_BASKETBALL_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/basketball/court.h"
|
||||
#include "scumm/he/basketball/basketball.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
class CBBallCourt;
|
||||
|
||||
class CCollisionBasketball : public CCollisionSphere {
|
||||
public:
|
||||
CCollisionBasketball() {}
|
||||
~CCollisionBasketball() {}
|
||||
|
||||
bool testCatch(const ICollisionObject &targetObject, U32Distance3D *distance, CBBallCourt *court);
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_BASKETBALL_H
|
||||
@@ -0,0 +1,59 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_box.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_node.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_tree.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
U32FltPoint3D CCollisionBox::findNearestPoint(const U32FltPoint3D &testPoint) const {
|
||||
U32FltPoint3D boxPoint;
|
||||
|
||||
for (int i = X_INDEX; i <= Z_INDEX; i++) {
|
||||
EDimension dimension = (EDimension)i;
|
||||
|
||||
if (testPoint[dimension] < minPoint[dimension]) {
|
||||
boxPoint[dimension] = minPoint[dimension];
|
||||
} else if (testPoint[dimension] > maxPoint[dimension]) {
|
||||
boxPoint[dimension] = maxPoint[dimension];
|
||||
} else {
|
||||
boxPoint[dimension] = testPoint[dimension];
|
||||
}
|
||||
}
|
||||
|
||||
return boxPoint;
|
||||
}
|
||||
|
||||
U32BoundingBox CCollisionBox::getBoundingBox() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
U32BoundingBox CCollisionBox::getBigBoundingBox() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
46
engines/scumm/he/basketball/collision/bball_collision_box.h
Normal file
46
engines/scumm/he/basketball/collision/bball_collision_box.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_BOX_H
|
||||
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_BOX_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
class CCollisionBox : public ICollisionObject, public U32BoundingBox {
|
||||
|
||||
public:
|
||||
CCollisionBox() : ICollisionObject(kBox) {}
|
||||
~CCollisionBox() {}
|
||||
|
||||
U32FltPoint3D findNearestPoint(const U32FltPoint3D &testPoint) const override;
|
||||
U32BoundingBox getBoundingBox() const override;
|
||||
U32BoundingBox getBigBoundingBox() const override;
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_BOX_H
|
||||
1130
engines/scumm/he/basketball/collision/bball_collision_cylinder.cpp
Normal file
1130
engines/scumm/he/basketball/collision/bball_collision_cylinder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
137
engines/scumm/he/basketball/collision/bball_collision_cylinder.h
Normal file
137
engines/scumm/he/basketball/collision/bball_collision_cylinder.h
Normal file
@@ -0,0 +1,137 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_CYLINDER_H
|
||||
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_CYLINDER_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define MAX_STEP_HEIGHT 50
|
||||
|
||||
// An object's velocity can either be carried
|
||||
// out as straight or circular movement...
|
||||
enum EMovementType {
|
||||
kStraight = 0,
|
||||
kCircular = 1 // 2D circular motion along the horizon plane
|
||||
};
|
||||
|
||||
class CCollisionCylinder : public ICollisionObject, public U32Cylinder {
|
||||
public:
|
||||
CCollisionCylinder() : ICollisionObject(kCylinder),
|
||||
height(0),
|
||||
_shieldRadius(0),
|
||||
_movementType(EMovementType::kStraight),
|
||||
_revCenter(nullptr),
|
||||
_positionSaved(false) {}
|
||||
|
||||
~CCollisionCylinder() {}
|
||||
|
||||
using ICollisionObject::getObjectDistance;
|
||||
float getObjectDistance(const CCollisionSphere &targetObject) const override;
|
||||
float getObjectDistance(const CCollisionBox &targetObject) const override;
|
||||
float getObjectDistance(const CCollisionCylinder &targetObject) const override;
|
||||
|
||||
using ICollisionObject::testObjectIntersection;
|
||||
bool testObjectIntersection(const CCollisionSphere &targetObject, U32Distance3D *distance) const override;
|
||||
bool testObjectIntersection(const CCollisionBox &targetObject, U32Distance3D *distance) const override;
|
||||
bool testObjectIntersection(const CCollisionCylinder &targetObject, U32Distance3D *distance) const override;
|
||||
|
||||
using ICollisionObject::validateCollision;
|
||||
bool validateCollision(const CCollisionCylinder &targetObject, U32Distance3D *distance) override;
|
||||
|
||||
using ICollisionObject::backOutOfObject;
|
||||
bool backOutOfObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed) override;
|
||||
bool backOutOfObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed) override;
|
||||
|
||||
using ICollisionObject::nudgeObject;
|
||||
bool nudgeObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed) override;
|
||||
bool nudgeObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed) override;
|
||||
|
||||
using ICollisionObject::isCollisionHandled;
|
||||
bool isCollisionHandled(const CCollisionSphere &targetObject) const override { return false; };
|
||||
|
||||
void handleCollisions(CCollisionObjectVector *collisionVector, float *timeUsed, bool advanceObject) override;
|
||||
void handleCollision(const CCollisionCylinder &targetCylinder, float *timeUsed, U32Distance3D *distance, bool advanceObject) override;
|
||||
void handleCollision(const CCollisionBox &targetBox, float *pTimeUsed, U32Distance3D *distance, bool advanceObject) override;
|
||||
|
||||
using ICollisionObject::isOnObject;
|
||||
bool isOnObject(const CCollisionSphere &targetObject, const U32Distance3D &distance) const override;
|
||||
bool isOnObject(const CCollisionBox &targetObject, const U32Distance3D &distance) const override;
|
||||
bool isOnObject(const CCollisionCylinder &targetObject, const U32Distance3D &distance) const override;
|
||||
|
||||
U32FltPoint3D findNearestPoint(const U32FltPoint3D &testPoint) const override;
|
||||
int getEquidistantPoint(U32FltPoint2D inPoint1, float distance1, U32FltPoint2D inPoint2, float distance2, U32FltPoint2D *outPoint1, U32FltPoint2D *outPoint2);
|
||||
|
||||
U32BoundingBox getBoundingBox() const override;
|
||||
U32BoundingBox getBigBoundingBox() const override;
|
||||
|
||||
void save() override;
|
||||
void restore() override;
|
||||
|
||||
float height;
|
||||
float _shieldRadius; // Sometimes we may want ot temporarily increase a player's
|
||||
// effective collision radius. This value keeps track of
|
||||
// how much their radius has been increased by.
|
||||
|
||||
EMovementType _movementType;
|
||||
|
||||
const ICollisionObject *_revCenter; // If an object is moving with circular motion,
|
||||
// this is the object it is revolving around.
|
||||
U32FltPoint2D _revCenterPt; // This is the center of the _revCenter.
|
||||
|
||||
protected:
|
||||
float getDimensionDistance(const CCollisionBox &targetObject, EDimension dimension) const;
|
||||
float getDimensionDistance(const CCollisionSphere &targetObject, EDimension dimension) const;
|
||||
float getDimensionDistance(const CCollisionCylinder &targetObject, EDimension dimension) const;
|
||||
|
||||
private:
|
||||
bool _positionSaved;
|
||||
U32FltPoint3D _safetyPoint;
|
||||
U32FltVector3D _safetyVelocity;
|
||||
|
||||
bool backStraightOutOfObject(const ICollisionObject &targetObject, U32Distance3D *distance, float *timeUsed);
|
||||
|
||||
bool circleOutOfObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed);
|
||||
bool circleOutOfObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed);
|
||||
|
||||
ERevDirection getRevDirection() const;
|
||||
|
||||
using ICollisionObject::getPenetrationTime;
|
||||
float getPenetrationTime(const CCollisionBox &targetObject, const U32Distance3D &distance, EDimension dimension) const override;
|
||||
float getPenetrationTime(const CCollisionCylinder &targetObject, const U32Distance3D &distance, EDimension dimension) const override;
|
||||
|
||||
float getPointOfCollision(const CCollisionBox &targetBox, U32Distance3D distance, EDimension dimension) const;
|
||||
|
||||
void forceOutOfObject(const ICollisionObject &targetObject, U32Distance3D *distance);
|
||||
|
||||
bool getCornerIntersection(const CCollisionBox &targetObject, const U32Distance3D &distance, U32FltPoint2D *intersection);
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_CYLINDER_H
|
||||
135
engines/scumm/he/basketball/collision/bball_collision_node.cpp
Normal file
135
engines/scumm/he/basketball/collision/bball_collision_node.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_box.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_node.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_tree.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
CCollisionNode::CCollisionNode() {
|
||||
for (int i = 0; i < NUM_CHILDREN_NODES; i++) {
|
||||
_child[i] = nullptr;
|
||||
}
|
||||
|
||||
_quadrant.setMinPoint(0, 0);
|
||||
_quadrant.setMaxPoint(0, 0);
|
||||
|
||||
_isExternal = false;
|
||||
}
|
||||
|
||||
CCollisionNode::CCollisionNode(const CCollisionObjectVector &initObjects) : _objectList(initObjects) {
|
||||
for (int i = 0; i < NUM_CHILDREN_NODES; i++) {
|
||||
_child[i] = nullptr;
|
||||
}
|
||||
|
||||
_quadrant.setMinPoint(0, 0);
|
||||
_quadrant.setMaxPoint(0, 0);
|
||||
|
||||
_isExternal = false;
|
||||
}
|
||||
|
||||
CCollisionNode::~CCollisionNode() {
|
||||
if (!_isExternal) {
|
||||
for (int i = 0; i < NUM_CHILDREN_NODES; i++) {
|
||||
assert(_child[i]);
|
||||
delete _child[i];
|
||||
_child[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U32BoundingBox CCollisionNode::getChildQuadrant(const U32BoundingBox &parentQuadrant, EChildID childID) {
|
||||
int minX, minY;
|
||||
int maxX, maxY;
|
||||
|
||||
int centerX = ((parentQuadrant.getMinPoint().x + parentQuadrant.getMaxPoint().x) / 2);
|
||||
int centerY = ((parentQuadrant.getMinPoint().y + parentQuadrant.getMaxPoint().y) / 2);
|
||||
|
||||
switch (childID) {
|
||||
|
||||
case kChild1:
|
||||
minX = centerX;
|
||||
minY = parentQuadrant.getMinPoint().y;
|
||||
maxX = parentQuadrant.getMaxPoint().x;
|
||||
maxY = centerY;
|
||||
break;
|
||||
|
||||
case kChild2:
|
||||
minX = centerX;
|
||||
minY = centerY;
|
||||
maxX = parentQuadrant.getMaxPoint().x;
|
||||
maxY = parentQuadrant.getMaxPoint().y;
|
||||
break;
|
||||
|
||||
case kChild3:
|
||||
minX = parentQuadrant.getMinPoint().x;
|
||||
minY = centerY;
|
||||
maxX = centerX;
|
||||
maxY = parentQuadrant.getMaxPoint().y;
|
||||
break;
|
||||
|
||||
case kChild4:
|
||||
minX = parentQuadrant.getMinPoint().x;
|
||||
minY = parentQuadrant.getMinPoint().y;
|
||||
maxX = centerX;
|
||||
maxY = centerY;
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("CCollisionNode::getChildQuadrant(): Invalid childID passed to getChildQuadrant");
|
||||
minX = 0;
|
||||
minY = 0;
|
||||
maxX = 0;
|
||||
maxY = 0;
|
||||
}
|
||||
|
||||
U32BoundingBox childQuadrant;
|
||||
childQuadrant.setMinPoint(minX, minY);
|
||||
childQuadrant.setMaxPoint(maxX, maxY);
|
||||
return childQuadrant;
|
||||
}
|
||||
|
||||
void CCollisionNode::searchTree(const U32BoundingBox &searchRange, CCollisionObjectVector *targetList) const {
|
||||
if (searchRange.intersect(_quadrant)) {
|
||||
if (_isExternal) {
|
||||
// Search through and add points that are within bounds...
|
||||
for (CCollisionObjectVector::size_type objectIndex = 0; objectIndex < _objectList.size(); ++objectIndex) {
|
||||
if (!_objectList[objectIndex]->_ignore) {
|
||||
const ICollisionObject *currentObject = _objectList[objectIndex];
|
||||
targetList->push_back(currentObject);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Search all of the children...
|
||||
for (int childID = 0; childID < NUM_CHILDREN_NODES; childID++) {
|
||||
_child[childID]->searchTree(searchRange, targetList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
70
engines/scumm/he/basketball/collision/bball_collision_node.h
Normal file
70
engines/scumm/he/basketball/collision/bball_collision_node.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_NODE_H
|
||||
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_NODE_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define NUM_CHILDREN_NODES 4
|
||||
|
||||
enum EChildID {
|
||||
kChild1 = 0,
|
||||
kChild2 = 1,
|
||||
kChild3 = 2,
|
||||
kChild4 = 3
|
||||
};
|
||||
|
||||
class CCollisionNode {
|
||||
public:
|
||||
CCollisionNode();
|
||||
CCollisionNode(const CCollisionObjectVector &initObjects);
|
||||
~CCollisionNode();
|
||||
|
||||
friend class CCollisionObjectTree;
|
||||
|
||||
private:
|
||||
void searchTree(const U32BoundingBox &searchRange, CCollisionObjectVector *targetList) const;
|
||||
static U32BoundingBox getChildQuadrant(const U32BoundingBox &parentQuadrant, EChildID childID);
|
||||
|
||||
// Children nodes to this node
|
||||
CCollisionNode *_child[NUM_CHILDREN_NODES];
|
||||
|
||||
// A list of object pointers that are contained within this node
|
||||
CCollisionObjectVector _objectList;
|
||||
|
||||
// The area that is handled by this node
|
||||
U32BoundingBox _quadrant;
|
||||
|
||||
// Whether or not this is a leaf node
|
||||
bool _isExternal;
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_NODE_H
|
||||
334
engines/scumm/he/basketball/collision/bball_collision_object.cpp
Normal file
334
engines/scumm/he/basketball/collision/bball_collision_object.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_box.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_node.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_tree.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
ICollisionObject::ICollisionObject(EObjectShape shape) : _objectShape(shape),
|
||||
_objectID(0),
|
||||
_objectType(kNoObjectType),
|
||||
_description(""),
|
||||
_collisionEfficiency(0.0F),
|
||||
_friction(0.0F),
|
||||
_soundNumber(0),
|
||||
_ignore(false) {
|
||||
_velocity.x = 0.0F;
|
||||
_velocity.y = 0.0F;
|
||||
_velocity.z = 0.0F;
|
||||
}
|
||||
|
||||
bool ICollisionObject::operator==(const ICollisionObject &otherObject) const {
|
||||
return ((otherObject._objectShape == _objectShape) &&
|
||||
(otherObject._objectType == _objectType) &&
|
||||
(otherObject._objectID == _objectID));
|
||||
}
|
||||
|
||||
float ICollisionObject::getObjectDistance(const ICollisionObject &targetObject) const {
|
||||
float result;
|
||||
|
||||
switch (targetObject._objectShape) {
|
||||
case kNoObjectShape:
|
||||
warning("ICollisionObject::getObjectDistance(): Tried to interact with an object of undefined type");
|
||||
result = 0.0F;
|
||||
break;
|
||||
case kSphere:
|
||||
result = getObjectDistance(dynamic_cast<const CCollisionSphere &>(targetObject));
|
||||
break;
|
||||
case kBox:
|
||||
result = getObjectDistance(dynamic_cast<const CCollisionBox &>(targetObject));
|
||||
break;
|
||||
case kCylinder:
|
||||
result = getObjectDistance(dynamic_cast<const CCollisionCylinder &>(targetObject));
|
||||
break;
|
||||
default:
|
||||
warning("ICollisionObject::getObjectDistance(): Tried to interact with an object of undefined type");
|
||||
result = 0.0F;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ICollisionObject::testObjectIntersection(const ICollisionObject &targetObject, U32Distance3D *distance) const {
|
||||
bool result;
|
||||
|
||||
switch (targetObject._objectShape) {
|
||||
case kNoObjectShape:
|
||||
warning("ICollisionObject::testObjectIntersection(): Tried to interact with an object of undefined type");
|
||||
result = false;
|
||||
break;
|
||||
case kSphere:
|
||||
result = testObjectIntersection(dynamic_cast<const CCollisionSphere &>(targetObject), distance);
|
||||
break;
|
||||
case kBox:
|
||||
result = testObjectIntersection(dynamic_cast<const CCollisionBox &>(targetObject), distance);
|
||||
break;
|
||||
case kCylinder:
|
||||
result = testObjectIntersection(dynamic_cast<const CCollisionCylinder &>(targetObject), distance);
|
||||
break;
|
||||
default:
|
||||
warning("ICollisionObject::testObjectIntersection(): Tried to interact with an object of undefined type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ICollisionObject::validateCollision(const ICollisionObject &targetObject, U32Distance3D *distance) {
|
||||
if (_ignore)
|
||||
return true;
|
||||
|
||||
bool result;
|
||||
|
||||
switch (targetObject._objectShape) {
|
||||
case kNoObjectShape:
|
||||
warning("ICollisionObject::validateCollision(): Tried to interact with an object of undefined type");
|
||||
result = false;
|
||||
break;
|
||||
case kSphere:
|
||||
result = validateCollision(dynamic_cast<const CCollisionSphere &>(targetObject), distance);
|
||||
break;
|
||||
case kBox:
|
||||
result = validateCollision(dynamic_cast<const CCollisionBox &>(targetObject), distance);
|
||||
break;
|
||||
case kCylinder:
|
||||
result = validateCollision(dynamic_cast<const CCollisionCylinder &>(targetObject), distance);
|
||||
break;
|
||||
default:
|
||||
warning("ICollisionObject::validateCollision(): Tried to interact with an object of undefined type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ICollisionObject::backOutOfObject(const ICollisionObject &targetObject, U32Distance3D *distance, float *timeUsed) {
|
||||
if (_ignore)
|
||||
return true;
|
||||
|
||||
bool result;
|
||||
|
||||
switch (targetObject._objectShape) {
|
||||
case kNoObjectShape:
|
||||
warning("ICollisionObject::backOutOfObject(): Tried to interact with an object of undefined type");
|
||||
result = false;
|
||||
break;
|
||||
case kSphere:
|
||||
result = backOutOfObject(dynamic_cast<const CCollisionSphere &>(targetObject), distance, timeUsed);
|
||||
break;
|
||||
case kBox:
|
||||
result = backOutOfObject(dynamic_cast<const CCollisionBox &>(targetObject), distance, timeUsed);
|
||||
break;
|
||||
case kCylinder:
|
||||
result = backOutOfObject(dynamic_cast<const CCollisionCylinder &>(targetObject), distance, timeUsed);
|
||||
break;
|
||||
default:
|
||||
warning("ICollisionObject::backOutOfObject(): Tried to interact with an object of undefined type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ICollisionObject::nudgeObject(const ICollisionObject &targetObject, U32Distance3D *distance, float *timeUsed) {
|
||||
if (_velocity.magnitude() == 0)
|
||||
return true;
|
||||
|
||||
if (_ignore)
|
||||
return true;
|
||||
|
||||
if (*timeUsed == 0)
|
||||
return true;
|
||||
|
||||
bool result;
|
||||
|
||||
switch (targetObject._objectShape) {
|
||||
case kNoObjectShape:
|
||||
warning("ICollisionObject::nudgeObject(): Tried to interact with an object of undefined type");
|
||||
result = false;
|
||||
break;
|
||||
case kSphere:
|
||||
result = nudgeObject(dynamic_cast<const CCollisionSphere &>(targetObject), distance, timeUsed);
|
||||
break;
|
||||
case kBox:
|
||||
result = nudgeObject(dynamic_cast<const CCollisionBox &>(targetObject), distance, timeUsed);
|
||||
break;
|
||||
case kCylinder:
|
||||
result = nudgeObject(dynamic_cast<const CCollisionCylinder &>(targetObject), distance, timeUsed);
|
||||
break;
|
||||
default:
|
||||
warning("ICollisionObject::nudgeObject(): Tried to interact with an object of undefined type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ICollisionObject::isCollisionHandled(const ICollisionObject &targetObject) const {
|
||||
bool result;
|
||||
|
||||
switch (targetObject._objectShape) {
|
||||
case kNoObjectShape:
|
||||
warning("ICollisionObject::isCollisionHandled(): Tried to interact with an object of undefined type");
|
||||
result = false;
|
||||
break;
|
||||
case kSphere:
|
||||
result = isCollisionHandled(dynamic_cast<const CCollisionSphere &>(targetObject));
|
||||
break;
|
||||
case kBox:
|
||||
result = isCollisionHandled(dynamic_cast<const CCollisionBox &>(targetObject));
|
||||
break;
|
||||
case kCylinder:
|
||||
result = isCollisionHandled(dynamic_cast<const CCollisionCylinder &>(targetObject));
|
||||
break;
|
||||
default:
|
||||
warning("ICollisionObject::isCollisionHandled(): Tried to interact with an object of undefined type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ICollisionObject::handleCollisions(CCollisionObjectVector *collisionVector, float *timeUsed, bool advanceObject) {
|
||||
if (_velocity.magnitude() == 0)
|
||||
return;
|
||||
|
||||
if (_ignore)
|
||||
return;
|
||||
|
||||
for (CCollisionObjectVector::const_iterator objectIt = collisionVector->begin(); objectIt != collisionVector->end(); ++objectIt) {
|
||||
const ICollisionObject *pTargetObject = *objectIt;
|
||||
|
||||
U32Distance3D distance;
|
||||
testObjectIntersection(*pTargetObject, &distance);
|
||||
|
||||
switch (pTargetObject->_objectShape) {
|
||||
case kNoObjectShape:
|
||||
warning("ICollisionObject::handleCollisions(): Tried to interact with an object of undefined type");
|
||||
break;
|
||||
case kSphere:
|
||||
handleCollision(*static_cast<const CCollisionSphere *>(pTargetObject), timeUsed, &distance, advanceObject);
|
||||
break;
|
||||
case kBox:
|
||||
handleCollision(*static_cast<const CCollisionBox *>(pTargetObject), timeUsed, &distance, advanceObject);
|
||||
break;
|
||||
case kCylinder:
|
||||
handleCollision(*static_cast<const CCollisionCylinder *>(pTargetObject), timeUsed, &distance, advanceObject);
|
||||
break;
|
||||
default:
|
||||
warning("ICollisionObject::handleCollisions(): Tried to interact with an object of undefined type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ICollisionObject::isOnObject(const ICollisionObject &targetObject, const U32Distance3D &distance) const {
|
||||
bool result;
|
||||
|
||||
switch (targetObject._objectShape) {
|
||||
case kNoObjectShape:
|
||||
warning("ICollisionObject::isOnObject(): Tried to interact with an object of undefined type");
|
||||
result = false;
|
||||
break;
|
||||
case kSphere:
|
||||
result = isOnObject(static_cast<const CCollisionSphere &>(targetObject), distance);
|
||||
break;
|
||||
case kBox:
|
||||
result = isOnObject(static_cast<const CCollisionBox &>(targetObject), distance);
|
||||
break;
|
||||
case kCylinder:
|
||||
result = isOnObject(static_cast<const CCollisionCylinder &>(targetObject), distance);
|
||||
break;
|
||||
default:
|
||||
warning("ICollisionObject::isOnObject(): Tried to interact with an object of undefined type");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
U32FltPoint3D ICollisionObject::findNearestPoint(const U32FltPoint3D &testPoint) const {
|
||||
return testPoint;
|
||||
}
|
||||
|
||||
float ICollisionObject::getPenetrationTime(const ICollisionObject &targetObject, const U32Distance3D &distance, EDimension dimension) const {
|
||||
float result;
|
||||
|
||||
switch (targetObject._objectShape) {
|
||||
case kNoObjectShape:
|
||||
warning("ICollisionObject::getPenetrationTime(): Tried to interact with an object of undefined type");
|
||||
result = 0.0F;
|
||||
break;
|
||||
case kSphere:
|
||||
result = getPenetrationTime(*static_cast<const CCollisionSphere *>(&targetObject), distance, dimension);
|
||||
break;
|
||||
case kBox:
|
||||
result = getPenetrationTime(*static_cast<const CCollisionBox *>(&targetObject), distance, dimension);
|
||||
break;
|
||||
case kCylinder:
|
||||
result = getPenetrationTime(*static_cast<const CCollisionCylinder *>(&targetObject), distance, dimension);
|
||||
break;
|
||||
default:
|
||||
warning("ICollisionObject::getPenetrationTime(): Tried to interact with an object of undefined type");
|
||||
result = 0.0F;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ICollisionObject::defineReflectionPlane(const ICollisionObject &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const {
|
||||
switch (targetObject._objectShape) {
|
||||
case kNoObjectShape:
|
||||
warning("ICollisionObject::defineReflectionPlane(): Tried to interact with an object of undefined type");
|
||||
break;
|
||||
case kSphere:
|
||||
defineReflectionPlane(dynamic_cast<const CCollisionSphere &>(targetObject), distance, collisionPlane);
|
||||
break;
|
||||
case kBox:
|
||||
defineReflectionPlane(dynamic_cast<const CCollisionBox &>(targetObject), distance, collisionPlane);
|
||||
break;
|
||||
case kCylinder:
|
||||
defineReflectionPlane(dynamic_cast<const CCollisionCylinder &>(targetObject), distance, collisionPlane);
|
||||
break;
|
||||
default:
|
||||
warning("ICollisionObject::defineReflectionPlane(): Tried to interact with an object of undefined type");
|
||||
}
|
||||
}
|
||||
|
||||
void ICollisionObject::defineReflectionPlane(const CCollisionSphere &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const {
|
||||
collisionPlane->clear();
|
||||
}
|
||||
|
||||
void ICollisionObject::defineReflectionPlane(const CCollisionBox &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const {
|
||||
collisionPlane->clear();
|
||||
}
|
||||
|
||||
void ICollisionObject::defineReflectionPlane(const CCollisionCylinder &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const {
|
||||
collisionPlane->clear();
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
193
engines/scumm/he/basketball/collision/bball_collision_object.h
Normal file
193
engines/scumm/he/basketball/collision/bball_collision_object.h
Normal file
@@ -0,0 +1,193 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_OBJECT_H
|
||||
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_OBJECT_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define COLLISION_EPSILON 0.5F
|
||||
#define COLLISION_SMALL_TIME_INCREMENT 0.05F
|
||||
#define COLLISION_BACK_OUT_TIME_LIMIT 20.0F
|
||||
|
||||
class CCollisionSphere;
|
||||
class CCollisionBox;
|
||||
class CCollisionCylinder;
|
||||
class CCollisionObjectStack;
|
||||
class CCollisionObjectVector;
|
||||
|
||||
enum EObjectShape {
|
||||
kNoObjectShape = 0,
|
||||
kSphere = 1,
|
||||
kBox = 2,
|
||||
kCylinder = 3
|
||||
};
|
||||
|
||||
enum EObjectType {
|
||||
kNoObjectType = 0,
|
||||
kBackboard = 1,
|
||||
kRim = 2,
|
||||
kOtherType = 3,
|
||||
kFloor = 4,
|
||||
kBall = 5,
|
||||
kPlayer = 6
|
||||
};
|
||||
|
||||
class ICollisionObject {
|
||||
public:
|
||||
ICollisionObject(EObjectShape shape = kNoObjectShape);
|
||||
virtual ~ICollisionObject() {}
|
||||
|
||||
// Comparison operator
|
||||
bool operator==(const ICollisionObject &otherObject) const;
|
||||
|
||||
// Get the distance between the outside of this object and the outside of a target object
|
||||
virtual float getObjectDistance(const ICollisionObject &targetObject) const;
|
||||
virtual float getObjectDistance(const CCollisionSphere &targetObject) const { return 0.0F; }
|
||||
virtual float getObjectDistance(const CCollisionBox &targetObject) const { return 0.0F; }
|
||||
virtual float getObjectDistance(const CCollisionCylinder &targetObject) const { return 0.0F; }
|
||||
|
||||
// testObjectIntersection is used to determine if this object is intersecting a target object
|
||||
virtual bool testObjectIntersection(const ICollisionObject &targetObject, U32Distance3D *distance) const;
|
||||
virtual bool testObjectIntersection(const CCollisionSphere &targetObject, U32Distance3D *distance) const { return false; }
|
||||
virtual bool testObjectIntersection(const CCollisionBox &targetObject, U32Distance3D *distance) const { return false; }
|
||||
virtual bool testObjectIntersection(const CCollisionCylinder &targetObject, U32Distance3D *distance) const { return false; }
|
||||
|
||||
// Just because this object is intersecting another, doesn't mean that it collided with
|
||||
// that object. That object could have collided with us. This function verifies, that
|
||||
// we collided with another object...
|
||||
virtual bool validateCollision(const ICollisionObject &targetObject, U32Distance3D *distance);
|
||||
virtual bool validateCollision(const CCollisionSphere &targetObject, U32Distance3D *distance) { return true; }
|
||||
virtual bool validateCollision(const CCollisionBox &targetObject, U32Distance3D *distance) { return true; }
|
||||
virtual bool validateCollision(const CCollisionCylinder &targetObject, U32Distance3D *distance) { return true; }
|
||||
|
||||
// backOutOfObject moves this object backwards along its velocity vector to a point
|
||||
// where it is guaranteed not to be intersecting a target object
|
||||
virtual bool backOutOfObject(const ICollisionObject &targetObject, U32Distance3D *distance, float *timeUsed);
|
||||
virtual bool backOutOfObject(const CCollisionSphere &targetObject, U32Distance3D *distance, float *timeUsed) { return true; }
|
||||
virtual bool backOutOfObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed) { return true; }
|
||||
virtual bool backOutOfObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed) { return true; }
|
||||
|
||||
// nudgeObject moves this object forward along its velocity vector to a point
|
||||
// where it is guaranteed to be touching the target object at the exact point
|
||||
// of collision
|
||||
virtual bool nudgeObject(const ICollisionObject &targetObject, U32Distance3D *distance, float *timeUsed);
|
||||
virtual bool nudgeObject(const CCollisionSphere &targetObject, U32Distance3D *distance, float *timeUsed) { return true; }
|
||||
virtual bool nudgeObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed) { return true; }
|
||||
virtual bool nudgeObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed) { return true; }
|
||||
|
||||
// Some collisions between objects are recorded, but not handled physically. This
|
||||
// function determines whether a collision gets handled or not...
|
||||
virtual bool isCollisionHandled(const ICollisionObject &targetObject) const;
|
||||
virtual bool isCollisionHandled(const CCollisionSphere &targetObject) const { return true; }
|
||||
virtual bool isCollisionHandled(const CCollisionBox &targetObject) const { return true; }
|
||||
virtual bool isCollisionHandled(const CCollisionCylinder &targetObject) const { return true; }
|
||||
|
||||
// handleCollisions alters this objects velocity and position as a result of
|
||||
// a collision with one or more target objects
|
||||
virtual void handleCollisions(CCollisionObjectVector *pCollisionVector, float *timeUsed, bool advanceObject);
|
||||
virtual void handleCollision(const CCollisionSphere &targetObject, float *timeUsed, U32Distance3D *distance, bool advanceObject) {}
|
||||
virtual void handleCollision(const CCollisionBox &targetObject, float *timeUsed, U32Distance3D *distance, bool advanceObject) {}
|
||||
virtual void handleCollision(const CCollisionCylinder &targetObject, float *timeUsed, U32Distance3D *distance, bool advanceObject) {}
|
||||
|
||||
// Determine if this object is resting, running, or rolling on another object.
|
||||
// An object doing this would not necessarily trigger an intersection...
|
||||
virtual bool isOnObject(const ICollisionObject &targetObject, const U32Distance3D &distance) const;
|
||||
virtual bool isOnObject(const CCollisionSphere &targetObject, const U32Distance3D &distance) const { return false; }
|
||||
virtual bool isOnObject(const CCollisionBox &targetObject, const U32Distance3D &distance) const { return false; }
|
||||
virtual bool isOnObject(const CCollisionCylinder &targetObject, const U32Distance3D &distance) const { return false; }
|
||||
|
||||
// Return a 3-dimensional bounding box for this object
|
||||
virtual U32BoundingBox getBoundingBox() const = 0;
|
||||
virtual U32BoundingBox getBigBoundingBox() const = 0;
|
||||
|
||||
// Return the point on the surface of the object that is closest to the input point
|
||||
virtual U32FltPoint3D findNearestPoint(const U32FltPoint3D &testPoint) const;
|
||||
|
||||
// Call this function when it is known that the object is at a legal location and is
|
||||
// not intersecting any other objects
|
||||
virtual void save() {}
|
||||
|
||||
// Put the object at the last place that it was guaranteed to not be intersecting any
|
||||
// other objects, and negate it's velocity vector
|
||||
virtual void restore() {}
|
||||
|
||||
Common::String _description;
|
||||
EObjectShape _objectShape;
|
||||
EObjectType _objectType;
|
||||
int _objectID; // An identifier that uniquely identifies this object
|
||||
|
||||
U32FltVector3D _velocity;
|
||||
|
||||
float _collisionEfficiency; // A multiplier (range 0 to 1) that represents
|
||||
// the percentage of velocity (perpendicular with
|
||||
// the collision) that a target object retains
|
||||
// when it collides with this object
|
||||
|
||||
float _friction; // A multiplier (range 0 to 1) that represents
|
||||
// the percentage of velocity (parallel with
|
||||
// the collision) that a target object loses
|
||||
// when it collides with this object
|
||||
|
||||
int _soundNumber;
|
||||
|
||||
bool _ignore; // There could be times when you want to ignore
|
||||
// an object for collision purposes. This flag
|
||||
// determines that.
|
||||
|
||||
CCollisionObjectVector _objectCollisionHistory; // Stack with pointers to all the
|
||||
// objects that this object collided
|
||||
// with this frame
|
||||
|
||||
CCollisionObjectVector _objectRollingHistory; // Stack with pointers to all the
|
||||
// objects that this object rolled
|
||||
// on this frame
|
||||
|
||||
protected:
|
||||
// Get the amount of time it took this sphere to penetrate whatever object it is
|
||||
// currently intersecting in the given dimension
|
||||
virtual float getPenetrationTime(const ICollisionObject &targetObject, const U32Distance3D &distance, EDimension dimension) const;
|
||||
virtual float getPenetrationTime(const CCollisionSphere &targetObject, const U32Distance3D &distance, EDimension dimension) const { return 0.0F; }
|
||||
virtual float getPenetrationTime(const CCollisionBox &targetObject, const U32Distance3D &distance, EDimension dimension) const { return 0.0F; }
|
||||
virtual float getPenetrationTime(const CCollisionCylinder &targetObject, const U32Distance3D &distance, EDimension dimension) const { return 0.0F; }
|
||||
|
||||
// Sometimes when this object collides with another object, it may want to treat
|
||||
// the object at the point of collision like a plane. This can help simplify the
|
||||
// collision. defineReflectionPlane defines a plane between this object and the
|
||||
// target object at the point of collision...
|
||||
virtual void defineReflectionPlane(const ICollisionObject &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const;
|
||||
virtual void defineReflectionPlane(const CCollisionSphere &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const;
|
||||
virtual void defineReflectionPlane(const CCollisionBox &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const;
|
||||
virtual void defineReflectionPlane(const CCollisionCylinder &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const;
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_OBJECT_H
|
||||
@@ -0,0 +1,95 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/basketball/court.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_player.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_box.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_node.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_tree.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
void CCollisionPlayer::startBlocking(int blockHeight, int blockTime) {
|
||||
assert(blockTime != 0);
|
||||
|
||||
_maxBlockHeight = blockHeight;
|
||||
_blockTime = blockTime;
|
||||
|
||||
int blockIncrement = _maxBlockHeight / _blockTime;
|
||||
|
||||
_blockHeight += blockIncrement;
|
||||
height += blockIncrement;
|
||||
}
|
||||
|
||||
void CCollisionPlayer::holdBlocking() {
|
||||
int blockIncrement = _maxBlockHeight / _blockTime;
|
||||
|
||||
if (_velocity.z > 0) {
|
||||
if ((_blockHeight + blockIncrement) <= _maxBlockHeight) {
|
||||
_blockHeight += blockIncrement;
|
||||
height += blockIncrement;
|
||||
} else {
|
||||
blockIncrement = _maxBlockHeight - _blockHeight;
|
||||
_blockHeight += blockIncrement;
|
||||
height += blockIncrement;
|
||||
|
||||
assert(_blockHeight == _maxBlockHeight);
|
||||
}
|
||||
} else if (_velocity.z < 0) {
|
||||
if ((_blockHeight - blockIncrement) >= 0) {
|
||||
_blockHeight -= blockIncrement;
|
||||
height -= blockIncrement;
|
||||
} else {
|
||||
blockIncrement = _blockHeight;
|
||||
_blockHeight -= blockIncrement;
|
||||
height -= blockIncrement;
|
||||
|
||||
assert(_blockHeight == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCollisionPlayer::endBlocking() {
|
||||
height -= _blockHeight;
|
||||
_blockHeight = 0;
|
||||
}
|
||||
|
||||
bool CCollisionPlayer::testCatch(const ICollisionObject &targetObject, U32Distance3D *distance, CBBallCourt *court) {
|
||||
if (&targetObject == (ICollisionObject *)&court->_virtualBall) {
|
||||
int oldHeight = height;
|
||||
height += _catchHeight;
|
||||
|
||||
bool retVal = testObjectIntersection(targetObject, distance);
|
||||
|
||||
height = oldHeight;
|
||||
|
||||
return retVal;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
@@ -0,0 +1,68 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_PLAYER_H
|
||||
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_PLAYER_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/basketball/court.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define PLAYER_CATCH_HEIGHT 250
|
||||
|
||||
class CBBallCourt;
|
||||
|
||||
class CCollisionPlayer : public CCollisionCylinder {
|
||||
public:
|
||||
CCollisionPlayer() : _playerHasBall(false),
|
||||
_playerIsInGame(true),
|
||||
_blockHeight(0),
|
||||
_blockTime(0),
|
||||
_catchHeight(0),
|
||||
_maxBlockHeight(0) {}
|
||||
|
||||
~CCollisionPlayer() {}
|
||||
|
||||
void startBlocking(int blockHeight, int blockTime);
|
||||
void holdBlocking();
|
||||
void endBlocking();
|
||||
|
||||
bool _playerHasBall;
|
||||
bool _playerIsInGame;
|
||||
|
||||
int _catchHeight; // The extra height that a player gets for detecting the ball.
|
||||
|
||||
bool testCatch(const ICollisionObject &targetObject, U32Distance3D *distance, CBBallCourt *court);
|
||||
|
||||
private:
|
||||
int _blockHeight = 0; // The extra height that a player gets when blocking.
|
||||
int _maxBlockHeight = 0; // The max extra height that a player gets when blocking.
|
||||
int _blockTime = 0; // The time it takes from the start of a block, to the apex of the block.
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_PLAYER_H
|
||||
@@ -0,0 +1,250 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/basketball/geo_translations.h"
|
||||
#include "scumm/he/basketball/court.h"
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_box.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_node.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_tree.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_shields.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
CCollisionShieldVector::CCollisionShieldVector() : _shieldUpCount(0) {
|
||||
CCollisionBox westShield;
|
||||
CCollisionBox northShield;
|
||||
CCollisionBox eastShield;
|
||||
CCollisionBox southShield;
|
||||
CCollisionBox topShield;
|
||||
|
||||
CCollisionBox westShield2;
|
||||
CCollisionBox northShield2;
|
||||
CCollisionBox eastShield2;
|
||||
CCollisionBox southShield2;
|
||||
|
||||
westShield.minPoint.x = 0 - SHIELD_DEPTH;
|
||||
westShield.maxPoint.x = 0;
|
||||
westShield.minPoint.y = 0 - SHIELD_EXTENSION;
|
||||
westShield.maxPoint.y = MAX_WORLD_Y + SHIELD_EXTENSION;
|
||||
westShield.minPoint.z = 0;
|
||||
westShield.maxPoint.z = SHIELD_HEIGHT;
|
||||
westShield._description = "West Shield";
|
||||
westShield._collisionEfficiency = 0.5F;
|
||||
westShield._friction = 0.3F;
|
||||
westShield._objectID = WEST_SHIELD_ID;
|
||||
westShield._ignore = true;
|
||||
|
||||
westShield2.minPoint.x = 0 - SHIELD_DEPTH - BUFFER_WIDTH;
|
||||
westShield2.maxPoint.x = 0 - BUFFER_WIDTH;
|
||||
westShield2.minPoint.y = 0 - SHIELD_EXTENSION;
|
||||
westShield2.maxPoint.y = MAX_WORLD_Y + SHIELD_EXTENSION;
|
||||
westShield2.minPoint.z = 0;
|
||||
westShield2.maxPoint.z = SHIELD_HEIGHT;
|
||||
westShield2._description = "West Shield 2";
|
||||
westShield2._collisionEfficiency = 0.5F;
|
||||
westShield2._friction = 0.3F;
|
||||
westShield2._objectID = BACKUP_WEST_SHIELD_ID;
|
||||
westShield2._ignore = true;
|
||||
|
||||
northShield.minPoint.x = 0 - SHIELD_EXTENSION;
|
||||
northShield.maxPoint.x = MAX_WORLD_X + SHIELD_EXTENSION;
|
||||
northShield.minPoint.y = MAX_WORLD_Y;
|
||||
northShield.maxPoint.y = MAX_WORLD_Y + SHIELD_DEPTH;
|
||||
northShield.minPoint.z = 0;
|
||||
northShield.maxPoint.z = SHIELD_HEIGHT;
|
||||
northShield._description = "North Shield";
|
||||
northShield._collisionEfficiency = 0.5F;
|
||||
northShield._friction = 0.3F;
|
||||
northShield._objectID = NORTH_SHIELD_ID;
|
||||
northShield._ignore = true;
|
||||
|
||||
northShield2.minPoint.x = 0 - SHIELD_EXTENSION;
|
||||
northShield2.maxPoint.x = MAX_WORLD_X + SHIELD_EXTENSION;
|
||||
northShield2.minPoint.y = MAX_WORLD_Y + BUFFER_WIDTH;
|
||||
northShield2.maxPoint.y = MAX_WORLD_Y + SHIELD_DEPTH + BUFFER_WIDTH;
|
||||
northShield2.minPoint.z = 0;
|
||||
northShield2.maxPoint.z = SHIELD_HEIGHT;
|
||||
northShield2._description = "North Shield 2";
|
||||
northShield2._collisionEfficiency = 0.5F;
|
||||
northShield2._friction = 0.3F;
|
||||
northShield2._objectID = BACKUP_NORTH_SHIELD_ID;
|
||||
northShield2._ignore = true;
|
||||
|
||||
eastShield.minPoint.x = MAX_WORLD_X;
|
||||
eastShield.maxPoint.x = MAX_WORLD_X + SHIELD_DEPTH;
|
||||
eastShield.minPoint.y = 0 - SHIELD_EXTENSION;
|
||||
eastShield.maxPoint.y = MAX_WORLD_Y + SHIELD_EXTENSION;
|
||||
eastShield.minPoint.z = 0;
|
||||
eastShield.maxPoint.z = SHIELD_HEIGHT;
|
||||
eastShield._description = "East Shield";
|
||||
eastShield._collisionEfficiency = 0.5F;
|
||||
eastShield._friction = 0.3F;
|
||||
eastShield._objectID = EAST_SHIELD_ID;
|
||||
eastShield._ignore = true;
|
||||
|
||||
eastShield2.minPoint.x = MAX_WORLD_X + BUFFER_WIDTH;
|
||||
eastShield2.maxPoint.x = MAX_WORLD_X + SHIELD_DEPTH + BUFFER_WIDTH;
|
||||
eastShield2.minPoint.y = 0 - SHIELD_EXTENSION;
|
||||
eastShield2.maxPoint.y = MAX_WORLD_Y + SHIELD_EXTENSION;
|
||||
eastShield2.minPoint.z = 0;
|
||||
eastShield2.maxPoint.z = SHIELD_HEIGHT;
|
||||
eastShield2._description = "East Shield 2";
|
||||
eastShield2._collisionEfficiency = 0.5F;
|
||||
eastShield2._friction = 0.3F;
|
||||
eastShield2._objectID = BACKUP_EAST_SHIELD_ID;
|
||||
eastShield2._ignore = true;
|
||||
|
||||
southShield.minPoint.x = 0 - SHIELD_EXTENSION;
|
||||
southShield.maxPoint.x = MAX_WORLD_X + SHIELD_EXTENSION;
|
||||
southShield.minPoint.y = 0 - SHIELD_DEPTH;
|
||||
southShield.maxPoint.y = 0;
|
||||
southShield.minPoint.z = 0;
|
||||
southShield.maxPoint.z = SHIELD_HEIGHT;
|
||||
southShield._description = "South Shield";
|
||||
southShield._collisionEfficiency = 0.5F;
|
||||
southShield._friction = 0.3F;
|
||||
southShield._objectID = SOUTH_SHIELD_ID;
|
||||
southShield._ignore = true;
|
||||
|
||||
southShield2.minPoint.x = 0 - SHIELD_EXTENSION;
|
||||
southShield2.maxPoint.x = MAX_WORLD_X + SHIELD_EXTENSION;
|
||||
southShield2.minPoint.y = 0 - SHIELD_DEPTH - BUFFER_WIDTH;
|
||||
southShield2.maxPoint.y = 0 - BUFFER_WIDTH;
|
||||
southShield2.minPoint.z = 0;
|
||||
southShield2.maxPoint.z = SHIELD_HEIGHT;
|
||||
southShield2._description = "South Shield 2";
|
||||
southShield2._collisionEfficiency = 0.5F;
|
||||
southShield2._friction = 0.3F;
|
||||
southShield2._objectID = BACKUP_SOUTH_SHIELD_ID;
|
||||
southShield2._ignore = true;
|
||||
|
||||
topShield.minPoint.x = 0 - SHIELD_EXTENSION;
|
||||
topShield.maxPoint.x = MAX_WORLD_X + SHIELD_EXTENSION;
|
||||
topShield.minPoint.y = 0 - SHIELD_EXTENSION;
|
||||
topShield.maxPoint.y = MAX_WORLD_Y + SHIELD_EXTENSION;
|
||||
topShield.minPoint.z = SHIELD_HEIGHT;
|
||||
topShield.maxPoint.z = SHIELD_HEIGHT + SHIELD_DEPTH;
|
||||
topShield._description = "Top Shield";
|
||||
topShield._collisionEfficiency = 0.5F;
|
||||
topShield._friction = 0.3F;
|
||||
topShield._objectID = TOP_SHIELD_ID;
|
||||
topShield._ignore = true;
|
||||
|
||||
push_back(westShield);
|
||||
push_back(northShield);
|
||||
push_back(eastShield);
|
||||
push_back(southShield);
|
||||
push_back(topShield);
|
||||
|
||||
push_back(westShield2);
|
||||
push_back(northShield2);
|
||||
push_back(eastShield2);
|
||||
push_back(southShield2);
|
||||
}
|
||||
|
||||
CCollisionShieldVector::~CCollisionShieldVector() {
|
||||
CCollisionShieldVector::iterator shieldIt;
|
||||
|
||||
for (shieldIt = begin(); shieldIt != end(); ++shieldIt) {
|
||||
shieldIt->_ignore = true;
|
||||
}
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userRaiseShields(int shieldID) {
|
||||
assert(shieldID < MAX_SHIELD_COUNT || shieldID == ALL_SHIELD_ID);
|
||||
|
||||
CCollisionShieldVector::iterator shieldIt;
|
||||
|
||||
for (shieldIt = _vm->_basketball->_shields->begin(); shieldIt != _vm->_basketball->_shields->end(); ++shieldIt) {
|
||||
// Make sure we don't mess with the backup shields...
|
||||
if (shieldIt->_objectID < MAX_SHIELD_COUNT) {
|
||||
if (((shieldIt->_objectID == shieldID) || (shieldID == ALL_SHIELD_ID)) &&
|
||||
(shieldIt->_ignore == true)) {
|
||||
shieldIt->_ignore = false;
|
||||
++_vm->_basketball->_shields->_shieldUpCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shieldID == ALL_SHIELD_ID) {
|
||||
assert(_vm->_basketball->_shields->_shieldUpCount == MAX_SHIELD_COUNT);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userLowerShields(int shieldID) {
|
||||
assert(shieldID < MAX_SHIELD_COUNT || shieldID == ALL_SHIELD_ID);
|
||||
|
||||
CCollisionShieldVector::iterator shieldIt;
|
||||
|
||||
for (shieldIt = _vm->_basketball->_shields->begin(); shieldIt != _vm->_basketball->_shields->end(); ++shieldIt) {
|
||||
// Make sure we don't mess with the backup shields...
|
||||
if (shieldIt->_objectID < MAX_SHIELD_COUNT) {
|
||||
if (((shieldIt->_objectID == shieldID) || (shieldID == ALL_SHIELD_ID)) &&
|
||||
(shieldIt->_ignore == false)) {
|
||||
shieldIt->_ignore = true;
|
||||
--_vm->_basketball->_shields->_shieldUpCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shieldID == ALL_SHIELD_ID) {
|
||||
assert(_vm->_basketball->_shields->_shieldUpCount == 0);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userAreShieldsClear() {
|
||||
int shieldsAreClear = (_vm->_basketball->_shields->_shieldUpCount != MAX_SHIELD_COUNT);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, shieldsAreClear);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userShieldPlayer(int playerID, int shieldRadius) {
|
||||
CCollisionPlayer *player = _vm->_basketball->_court->getPlayerPtr(playerID);
|
||||
|
||||
if (player->_shieldRadius < shieldRadius) {
|
||||
player->_shieldRadius += PLAYER_SHIELD_INCREMENT_VALUE;
|
||||
player->radius += PLAYER_SHIELD_INCREMENT_VALUE;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userClearPlayerShield(int playerID) {
|
||||
CCollisionPlayer *player = _vm->_basketball->_court->getPlayerPtr(playerID);
|
||||
|
||||
player->radius -= player->_shieldRadius;
|
||||
player->_shieldRadius = 0.0F;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
@@ -0,0 +1,64 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SHIELDS_H
|
||||
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SHIELDS_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_box.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define WEST_SHIELD_ID 0
|
||||
#define NORTH_SHIELD_ID 1
|
||||
#define EAST_SHIELD_ID 2
|
||||
#define SOUTH_SHIELD_ID 3
|
||||
#define TOP_SHIELD_ID 4
|
||||
#define ALL_SHIELD_ID 5
|
||||
#define MAX_SHIELD_COUNT 5
|
||||
|
||||
#define BACKUP_WEST_SHIELD_ID 6
|
||||
#define BACKUP_NORTH_SHIELD_ID 7
|
||||
#define BACKUP_EAST_SHIELD_ID 8
|
||||
#define BACKUP_SOUTH_SHIELD_ID 9
|
||||
|
||||
#define PLAYER_SHIELD_INCREMENT_VALUE 25
|
||||
|
||||
#define SHIELD_DEPTH 1000
|
||||
#define SHIELD_HEIGHT 50000
|
||||
#define SHIELD_EXTENSION 20000
|
||||
#define BUFFER_WIDTH 800
|
||||
|
||||
class CCollisionShieldVector : public Common::Array<CCollisionBox> {
|
||||
public:
|
||||
CCollisionShieldVector();
|
||||
~CCollisionShieldVector();
|
||||
|
||||
int _shieldUpCount;
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SHIELDS_H
|
||||
662
engines/scumm/he/basketball/collision/bball_collision_sphere.cpp
Normal file
662
engines/scumm/he/basketball/collision/bball_collision_sphere.cpp
Normal file
@@ -0,0 +1,662 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_box.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_node.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_tree.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
float CCollisionSphere::getDimensionDistance(const CCollisionBox &targetObject, EDimension dimension) const {
|
||||
if (center[dimension] < targetObject.minPoint[dimension]) {
|
||||
return (center[dimension] - targetObject.minPoint[dimension]);
|
||||
} else if (center[dimension] > targetObject.maxPoint[dimension]) {
|
||||
return (center[dimension] - targetObject.maxPoint[dimension]);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
float CCollisionSphere::getDimensionDistance(const CCollisionCylinder &targetObject, EDimension dimension) const {
|
||||
float centerDistance = center[dimension] - targetObject.center[dimension];
|
||||
|
||||
if (dimension == Z_INDEX) {
|
||||
if (centerDistance < -(targetObject.height / 2)) {
|
||||
return (centerDistance + (targetObject.height / 2));
|
||||
} else if (centerDistance > (targetObject.height / 2)) {
|
||||
return (centerDistance - (targetObject.height / 2));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return centerDistance;
|
||||
}
|
||||
}
|
||||
|
||||
float CCollisionSphere::getObjectDistance(const CCollisionBox &targetObject) const {
|
||||
U32Distance3D distance;
|
||||
|
||||
distance.x = getDimensionDistance(targetObject, X_INDEX);
|
||||
distance.y = getDimensionDistance(targetObject, Y_INDEX);
|
||||
distance.z = getDimensionDistance(targetObject, Z_INDEX);
|
||||
|
||||
float totalDistance = distance.magnitude() - radius;
|
||||
if (totalDistance < 0)
|
||||
totalDistance = 0;
|
||||
|
||||
return totalDistance;
|
||||
}
|
||||
|
||||
float CCollisionSphere::getObjectDistance(const CCollisionCylinder &targetObject) const {
|
||||
U32Distance3D distance;
|
||||
|
||||
distance.x = getDimensionDistance(targetObject, X_INDEX);
|
||||
distance.y = getDimensionDistance(targetObject, Y_INDEX);
|
||||
distance.z = getDimensionDistance(targetObject, Z_INDEX);
|
||||
|
||||
float xyDistance = distance.xyMagnitude() - radius - targetObject.radius;
|
||||
if (xyDistance < 0)
|
||||
xyDistance = 0;
|
||||
|
||||
float zDistance = fabs(distance.z) - radius - (targetObject.height / 2);
|
||||
if (zDistance < 0)
|
||||
zDistance = 0;
|
||||
|
||||
float totalDistance = sqrt((xyDistance * xyDistance) + (zDistance * zDistance));
|
||||
|
||||
return totalDistance;
|
||||
}
|
||||
|
||||
bool CCollisionSphere::testObjectIntersection(const CCollisionBox &targetObject, U32Distance3D *distance) const {
|
||||
// Get the distance between the ball and the bounding box...
|
||||
distance->x = getDimensionDistance(targetObject, X_INDEX);
|
||||
distance->y = getDimensionDistance(targetObject, Y_INDEX);
|
||||
distance->z = getDimensionDistance(targetObject, Z_INDEX);
|
||||
|
||||
// Determine if the ball intersects the bounding box.
|
||||
return (distance->magnitude() < radius);
|
||||
}
|
||||
|
||||
bool CCollisionSphere::testObjectIntersection(const CCollisionCylinder &targetObject, U32Distance3D *distance) const {
|
||||
// Get the distance between the ball and the cylinder...
|
||||
distance->x = getDimensionDistance(targetObject, X_INDEX);
|
||||
distance->y = getDimensionDistance(targetObject, Y_INDEX);
|
||||
distance->z = getDimensionDistance(targetObject, Z_INDEX);
|
||||
|
||||
if (distance->xyMagnitude() < (radius + targetObject.radius)) {
|
||||
return (fabs(distance->z) < radius);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CCollisionSphere::validateCollision(const CCollisionBox &targetObject, U32Distance3D *distance) {
|
||||
U32FltPoint3D targetPoint = targetObject.findNearestPoint(center);
|
||||
U32FltVector3D centerVector = targetPoint - center;
|
||||
float aMag = _velocity.magnitude();
|
||||
float bMag = centerVector.magnitude();
|
||||
float aDotb = _velocity * centerVector;
|
||||
|
||||
if (aMag == 0) {
|
||||
// If this object isn't moving, this can't be a valid collision...
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bMag == 0) {
|
||||
// bMag is 0, it is possible that this sphere penetrated too far into the target
|
||||
// object. If this is the case, we'll go ahead and validate the collision...
|
||||
return true;
|
||||
}
|
||||
|
||||
double angleCosine = aDotb / (aMag * bMag);
|
||||
|
||||
if (angleCosine > 1) {
|
||||
angleCosine = 1;
|
||||
} else if (angleCosine < -1) {
|
||||
angleCosine = -1;
|
||||
}
|
||||
|
||||
float sourceMovementAngle = acos(angleCosine);
|
||||
|
||||
if (sourceMovementAngle < (BBALL_M_PI / 2)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CCollisionSphere::validateCollision(const CCollisionCylinder &targetObject, U32Distance3D *distance) {
|
||||
// Create a vector from the center of the target cylinder to the center of
|
||||
// this sphere. If the sphere is not hitting above or below the cylinder,
|
||||
// negate any z component of the center vector...
|
||||
U32FltVector3D centerVector = targetObject.center - center;
|
||||
|
||||
if (center.z > (targetObject.center.z + targetObject.height / 2)) {
|
||||
centerVector.z = targetObject.center.z + (targetObject.height / 2) - center.z;
|
||||
} else if (center.z < (targetObject.center.z - targetObject.height / 2)) {
|
||||
centerVector.z = targetObject.center.z - (targetObject.height / 2) - center.z;
|
||||
} else if (_velocity.xyMagnitude() != 0) {
|
||||
centerVector.z = 0;
|
||||
}
|
||||
|
||||
float aMag = _velocity.magnitude();
|
||||
float bMag = centerVector.magnitude();
|
||||
float aDotb = _velocity * centerVector;
|
||||
|
||||
if (aMag == 0) {
|
||||
// If this object isn't moving, this can't be a valid collision...
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bMag == 0) {
|
||||
// bMag is 0, it is possible that this sphere penetrated too far into the target
|
||||
// object. If this is the case, we'll go ahead and validate the collision...
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate the angle between this object's velocity and the vector from the target
|
||||
// objects center to our center. If the angle between the two is greater than
|
||||
// 90 degrees, then the target object is not colliding with us...
|
||||
double angleCosine = aDotb / (aMag * bMag);
|
||||
|
||||
if (angleCosine > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
float CCollisionSphere::getPenetrationTime(const CCollisionBox &targetObject, const U32Distance3D &distance, EDimension dimension) const {
|
||||
float collisionDepth1;
|
||||
float collisionDepth2;
|
||||
|
||||
float boxWidth = targetObject.maxPoint[dimension] - targetObject.minPoint[dimension];
|
||||
|
||||
if (distance[dimension] > 0) {
|
||||
collisionDepth1 = (radius - distance[dimension]);
|
||||
collisionDepth2 = (-radius + distance[dimension] - boxWidth);
|
||||
} else if (distance[dimension] < 0) {
|
||||
collisionDepth1 = (-radius - distance[dimension]);
|
||||
collisionDepth2 = (radius - distance[dimension] + boxWidth);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float time1 = (_velocity[dimension] == 0) ? 0 : collisionDepth1 / -_velocity[dimension];
|
||||
float time2 = (_velocity[dimension] == 0) ? 0 : collisionDepth2 / -_velocity[dimension];
|
||||
float tFinal = MIN_GREATER_THAN_ZERO(time1, time2);
|
||||
|
||||
return tFinal;
|
||||
}
|
||||
|
||||
float CCollisionSphere::getPenetrationTime(const CCollisionCylinder &targetObject, const U32Distance3D &distance, EDimension dimension) const {
|
||||
float collisionDepth;
|
||||
|
||||
if (dimension == Z_INDEX) {
|
||||
if (distance[dimension] > 0) {
|
||||
collisionDepth = (radius - distance[dimension]);
|
||||
} else if (distance[dimension] < 0) {
|
||||
collisionDepth = (-radius - distance[dimension]);
|
||||
} else {
|
||||
collisionDepth = 0;
|
||||
}
|
||||
} else {
|
||||
if (distance[dimension] > 0) {
|
||||
collisionDepth = (radius + targetObject.radius - distance[dimension]);
|
||||
} else if (distance[dimension] < 0) {
|
||||
collisionDepth = (-radius - targetObject.radius - distance[dimension]);
|
||||
} else {
|
||||
collisionDepth = 0;
|
||||
}
|
||||
}
|
||||
|
||||
float tFinal = (_velocity[dimension] == 0) ? 0 : (collisionDepth / -_velocity[dimension]);
|
||||
return tFinal;
|
||||
}
|
||||
|
||||
bool CCollisionSphere::backStraightOutOfObject(const ICollisionObject &targetObject, U32Distance3D *distance, float *timeUsed) {
|
||||
if (_velocity.magnitude() == 0)
|
||||
return true;
|
||||
|
||||
U32FltPoint3D startPosition = center;
|
||||
|
||||
int loopCounter = 0;
|
||||
|
||||
while (testObjectIntersection(targetObject, distance)) {
|
||||
float collisionTimes[3];
|
||||
|
||||
collisionTimes[X_INDEX] = getPenetrationTime(targetObject, *distance, X_INDEX);
|
||||
collisionTimes[Y_INDEX] = getPenetrationTime(targetObject, *distance, Y_INDEX);
|
||||
collisionTimes[Z_INDEX] = getPenetrationTime(targetObject, *distance, Z_INDEX);
|
||||
|
||||
Std::sort(collisionTimes, collisionTimes + Z_INDEX + 1);
|
||||
|
||||
float collisionTime = COLLISION_SMALL_TIME_INCREMENT;
|
||||
if (collisionTimes[2] > 0)
|
||||
collisionTime = collisionTimes[2];
|
||||
if (collisionTimes[1] > 0)
|
||||
collisionTime = collisionTimes[1];
|
||||
if (collisionTimes[0] > 0)
|
||||
collisionTime = collisionTimes[0];
|
||||
|
||||
*timeUsed += collisionTime;
|
||||
|
||||
// If we take too long to back out, something is wrong.
|
||||
// Restore the object to an ok state...
|
||||
if ((*timeUsed > COLLISION_BACK_OUT_TIME_LIMIT) && (*timeUsed != collisionTime)) {
|
||||
warning("CCollisionSphere::backStraightOutOfObject(): It took too long for one object to back out of another. Ignore and U32 will attempt to correct.");
|
||||
center = startPosition;
|
||||
restore();
|
||||
return false;
|
||||
}
|
||||
|
||||
center.x -= (collisionTime * _velocity.x);
|
||||
center.y -= (collisionTime * _velocity.y);
|
||||
center.z -= (collisionTime * _velocity.z);
|
||||
|
||||
// Make doubly sure we don't loop forever...
|
||||
if (++loopCounter > 500)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCollisionSphere::backOutOfObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed) {
|
||||
return backStraightOutOfObject(targetObject, distance, timeUsed);
|
||||
}
|
||||
|
||||
bool CCollisionSphere::backOutOfObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed) {
|
||||
return backStraightOutOfObject(targetObject, distance, timeUsed);
|
||||
}
|
||||
|
||||
bool CCollisionSphere::nudgeObject(const CCollisionBox &targetObject, U32Distance3D *distance, float *timeUsed) {
|
||||
// To nudge the sphere precisely against the box, we need to calculate when the
|
||||
// square root of the sum of the squared distances between the sphere and the three
|
||||
// planes equals the radius of the sphere. Here we will construct a quadratic
|
||||
// equation to solve for time....
|
||||
|
||||
double a = 0;
|
||||
double b = 0;
|
||||
double c = -(radius * radius);
|
||||
|
||||
for (int i = X_INDEX; i <= Z_INDEX; ++i) {
|
||||
EDimension dim = (EDimension)i;
|
||||
|
||||
// If the ball is already within the boundaries of the box in a certain dimension,
|
||||
// we don't want to include that dimension in the equation...
|
||||
if ((*distance)[dim] != 0) {
|
||||
a += (_velocity[dim] * _velocity[dim]);
|
||||
b += (2 * _velocity[dim] * (*distance)[dim]);
|
||||
c += ((*distance)[dim] * (*distance)[dim]);
|
||||
}
|
||||
}
|
||||
|
||||
if (((b * b) < (4 * a * c)) || (a == 0)) {
|
||||
warning("CCollisionSphere::nudgeObject(): Tried to use sqrt on a negative number");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now we have two answer candidates. We want the smallest of the two that is
|
||||
// greater than 0...
|
||||
double t1 = (-b + sqrt(b * b - 4 * a * c)) / (2 * a);
|
||||
double t2 = (-b - sqrt(b * b - 4 * a * c)) / (2 * a);
|
||||
|
||||
double tFinal = 0;
|
||||
if ((0 <= t1) && (t1 <= t2)) {
|
||||
tFinal = t1;
|
||||
} else if ((0 <= t2) && (t2 <= t1)) {
|
||||
tFinal = t2;
|
||||
}
|
||||
|
||||
// Update the position of the ball...
|
||||
center.x += _velocity.x * tFinal;
|
||||
center.y += _velocity.y * tFinal;
|
||||
center.z += _velocity.z * tFinal;
|
||||
*timeUsed -= tFinal;
|
||||
|
||||
testObjectIntersection(targetObject, distance);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCollisionSphere::nudgeObject(const CCollisionCylinder &targetObject, U32Distance3D *distance, float *timeUsed) {
|
||||
float collisionTimeFinal;
|
||||
|
||||
U32FltVector3D xyVelocity = _velocity;
|
||||
xyVelocity.z = 0;
|
||||
|
||||
// Find the distance between the two centers that would indicate an exact collision...
|
||||
float intersectionDist = radius + targetObject.radius;
|
||||
|
||||
// Set up a vector pointing from the center of this sphere to the center of
|
||||
// the target cylinder...
|
||||
U32FltVector3D centerVector;
|
||||
centerVector.x = targetObject.center.x - center.x;
|
||||
centerVector.y = targetObject.center.y - center.y;
|
||||
|
||||
float centerDistance = centerVector.xyMagnitude();
|
||||
|
||||
if (centerDistance > intersectionDist) {
|
||||
// Project the center vector onto the velocity vector.
|
||||
// This is the distance along the velocity vector from the
|
||||
// center of the sphere to the point that is parallel with the center
|
||||
// of the cylinder...
|
||||
float parallelDistance = centerVector.projectScalar(xyVelocity);
|
||||
|
||||
// Find the distance between the center of the target object to the point that
|
||||
// that is distance2 units along the the velocity vector...
|
||||
parallelDistance = ((centerDistance * centerDistance) >=
|
||||
(parallelDistance * parallelDistance))
|
||||
? parallelDistance
|
||||
: COPY_SIGN(centerDistance, parallelDistance);
|
||||
|
||||
// Make sure we don't try to sqrt by negative number...
|
||||
if (parallelDistance > centerDistance) {
|
||||
warning("CCollisionSphere::nudgeObject(): Tried to sqrt by negative number.");
|
||||
centerDistance = parallelDistance;
|
||||
}
|
||||
|
||||
float perdistance = sqrt(centerDistance * centerDistance - parallelDistance * parallelDistance);
|
||||
|
||||
// Now we need to find the point along the velocity vector where the distance
|
||||
// between that point and the center of the target cylinder equals intersectionDist.
|
||||
// We calculate using distance 2, distance3 and intersectionDist...
|
||||
perdistance = ((intersectionDist * intersectionDist) >=
|
||||
(perdistance * perdistance))
|
||||
? perdistance
|
||||
: COPY_SIGN(intersectionDist, perdistance);
|
||||
|
||||
// Make sure we don't try to sqrt by negative number...
|
||||
if (perdistance > intersectionDist) {
|
||||
warning("CCollisionSphere::nudgeObject(): Tried to sqrt by negative number.");
|
||||
intersectionDist = perdistance;
|
||||
}
|
||||
|
||||
float xyCollisionDist = parallelDistance - sqrt(intersectionDist * intersectionDist - perdistance * perdistance);
|
||||
collisionTimeFinal = (_velocity.xyMagnitude() == 0) ? 0 : (xyCollisionDist / _velocity.xyMagnitude());
|
||||
} else {
|
||||
collisionTimeFinal = -getPenetrationTime(targetObject, *distance, Z_INDEX);
|
||||
}
|
||||
|
||||
center.x += collisionTimeFinal * _velocity.x;
|
||||
center.y += collisionTimeFinal * _velocity.y;
|
||||
center.z += collisionTimeFinal * _velocity.z;
|
||||
*timeUsed -= collisionTimeFinal;
|
||||
|
||||
testObjectIntersection(targetObject, distance);
|
||||
|
||||
// We may still have a little ways to go in the z direction...
|
||||
if (fabs(distance->z) >= (radius + COLLISION_EPSILON)) {
|
||||
collisionTimeFinal = -getPenetrationTime(targetObject, *distance, Z_INDEX);
|
||||
|
||||
center.x += collisionTimeFinal * _velocity.x;
|
||||
center.y += collisionTimeFinal * _velocity.y;
|
||||
center.z += collisionTimeFinal * _velocity.z;
|
||||
*timeUsed -= collisionTimeFinal;
|
||||
|
||||
testObjectIntersection(targetObject, distance);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCollisionSphere::defineReflectionPlane(const CCollisionBox &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const {
|
||||
// Find the point of collision...
|
||||
collisionPlane->point = targetObject.findNearestPoint(center);
|
||||
|
||||
// Find the normal of the collision plane...
|
||||
collisionPlane->normal.x = (distance.magnitude() == 0) ? 0 : distance.x / distance.magnitude();
|
||||
collisionPlane->normal.y = (distance.magnitude() == 0) ? 0 : distance.y / distance.magnitude();
|
||||
collisionPlane->normal.z = (distance.magnitude() == 0) ? 0 : distance.z / distance.magnitude();
|
||||
|
||||
collisionPlane->friction = targetObject._friction;
|
||||
collisionPlane->collisionEfficiency = targetObject._collisionEfficiency;
|
||||
}
|
||||
|
||||
void CCollisionSphere::defineReflectionPlane(const CCollisionCylinder &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const {
|
||||
// Find the point of collision...
|
||||
collisionPlane->point = targetObject.findNearestPoint(center);
|
||||
|
||||
// Find the normal of the collision plane...
|
||||
collisionPlane->normal.x = (distance.magnitude() == 0) ? 0 : distance.x / distance.magnitude();
|
||||
collisionPlane->normal.y = (distance.magnitude() == 0) ? 0 : distance.y / distance.magnitude();
|
||||
collisionPlane->normal.z = (distance.magnitude() == 0) ? 0 : distance.z / distance.magnitude();
|
||||
|
||||
collisionPlane->friction = targetObject._friction;
|
||||
collisionPlane->collisionEfficiency = targetObject._collisionEfficiency;
|
||||
}
|
||||
|
||||
void CCollisionSphere::reboundOffPlane(const U32Plane &collisionPlane, bool isOnObject) {
|
||||
U32FltVector3D normalVector;
|
||||
U32FltVector3D reflectionVector;
|
||||
U32FltVector3D parallelVector;
|
||||
U32FltVector3D perpendicularVector;
|
||||
|
||||
// Calculate the reflection vector...
|
||||
normalVector = _velocity.projectVector(collisionPlane.normal) * -1;
|
||||
reflectionVector = (normalVector * 2) + _velocity;
|
||||
|
||||
// Break down the components of the refelction vector that are perpendicular
|
||||
// and parallel to the collision plane. This way we can account for drag and
|
||||
// inelastic collisions...
|
||||
perpendicularVector = normalVector;
|
||||
perpendicularVector *= collisionPlane.collisionEfficiency * _collisionEfficiency;
|
||||
|
||||
parallelVector = reflectionVector - normalVector;
|
||||
|
||||
if ((!isOnObject) || ((_rollingCount % ROLL_SLOWDOWN_FREQUENCY) == 0)) {
|
||||
parallelVector -= ((parallelVector * collisionPlane.friction) + (parallelVector * _friction));
|
||||
}
|
||||
|
||||
// Now put the reflection vector back together again...
|
||||
reflectionVector = parallelVector + perpendicularVector;
|
||||
|
||||
_velocity = reflectionVector;
|
||||
}
|
||||
|
||||
void CCollisionSphere::increaseVelocity(float minSpeed) {
|
||||
if (_velocity.magnitude() < minSpeed) {
|
||||
// Make sure we're moving along the XY plane...
|
||||
if (_velocity.xyMagnitude() == 0) {
|
||||
// Randomly add some velocity...
|
||||
int random = (g_scumm->_rnd.getRandomNumber(0x7FFF) * 4) / 0x7FFF;
|
||||
switch (random) {
|
||||
case 0:
|
||||
_velocity.x = minSpeed;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
_velocity.x = -minSpeed;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
_velocity.y = minSpeed;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
case 4:
|
||||
_velocity.y = -minSpeed;
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("CCollisionSphere::increaseVelocity(): Invalid random number.");
|
||||
}
|
||||
} else {
|
||||
// Increase the current velocity...
|
||||
float oldVelocity = _velocity.magnitude();
|
||||
_velocity.x = (_velocity.x / oldVelocity) * minSpeed;
|
||||
_velocity.y = (_velocity.y / oldVelocity) * minSpeed;
|
||||
_velocity.z = (_velocity.z / oldVelocity) * minSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCollisionSphere::handleCollisions(CCollisionObjectVector *collisionVector, float *timeUsed, bool advanceObject) {
|
||||
Common::Array<U32Plane> planeVector;
|
||||
Common::Array<bool> rollingRecord;
|
||||
U32Plane collisionPlane;
|
||||
U32Distance3D distance;
|
||||
bool isRollingOnObject;
|
||||
|
||||
for (CCollisionObjectVector::const_iterator objectIt = collisionVector->begin();
|
||||
objectIt != collisionVector->end();
|
||||
++objectIt) {
|
||||
const ICollisionObject *currentObject = *objectIt;
|
||||
|
||||
testObjectIntersection(*currentObject, &distance);
|
||||
|
||||
// See if we are rolling on this object...
|
||||
isRollingOnObject = isOnObject(*currentObject, distance);
|
||||
if (isRollingOnObject) {
|
||||
// See if rolling has slowed to the point that we are stopped.
|
||||
// Never stop on the backboard or rim...
|
||||
if ((currentObject->_objectType == kBackboard) ||
|
||||
(currentObject->_objectType == kRim)) {
|
||||
increaseVelocity(ROLL_SPEED_LIMIT);
|
||||
} else {
|
||||
if (_velocity.xyMagnitude() < ROLL_SPEED_LIMIT) {
|
||||
_velocity.x = 0;
|
||||
_velocity.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_velocity.z = 0;
|
||||
} else {
|
||||
// See if rolling has slowed to the point that we are stopped.
|
||||
// Never stop on the backboard or rim...
|
||||
if ((currentObject->_objectType == kBackboard) ||
|
||||
(currentObject->_objectType == kRim)) {
|
||||
increaseVelocity(ROLL_SPEED_LIMIT);
|
||||
}
|
||||
}
|
||||
|
||||
defineReflectionPlane(*currentObject, distance, &collisionPlane);
|
||||
planeVector.push_back(collisionPlane);
|
||||
rollingRecord.push_back(isRollingOnObject);
|
||||
}
|
||||
|
||||
collisionVector->clear();
|
||||
|
||||
if (!planeVector.empty()) {
|
||||
collisionPlane = planeVector[0];
|
||||
isRollingOnObject = rollingRecord[0];
|
||||
|
||||
Common::Array<U32Plane>::const_iterator planeIt;
|
||||
Common::Array<bool>::const_iterator recordIt;
|
||||
|
||||
for (planeIt = planeVector.begin(), recordIt = rollingRecord.begin();
|
||||
planeIt != planeVector.end();
|
||||
++planeIt, ++recordIt) {
|
||||
|
||||
collisionPlane.average(*planeIt);
|
||||
isRollingOnObject = isRollingOnObject || *recordIt;
|
||||
}
|
||||
|
||||
reboundOffPlane(collisionPlane, isRollingOnObject);
|
||||
}
|
||||
|
||||
if (advanceObject) {
|
||||
// Move the ball for the amount of time remaining...
|
||||
center.x += (_velocity.x * *timeUsed);
|
||||
center.y += (_velocity.y * *timeUsed);
|
||||
center.z += (_velocity.z * *timeUsed);
|
||||
|
||||
*timeUsed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool CCollisionSphere::isOnObject(const CCollisionBox &targetObject, const U32Distance3D &distance) const {
|
||||
float distancePercentage = fabs(distance.z - radius) / radius;
|
||||
|
||||
// See if bouncing has slowed to the point that we are rolling...
|
||||
return ((distancePercentage < .1) &&
|
||||
(distance.xyMagnitude() == 0) &&
|
||||
(fabs(_velocity.z) <= BOUNCE_SPEED_LIMIT));
|
||||
}
|
||||
|
||||
bool CCollisionSphere::isOnObject(const CCollisionCylinder &targetObject, const U32Distance3D &distance) const {
|
||||
float distancePercentage = fabs(distance.z - radius) / radius;
|
||||
|
||||
// See if bouncing has slowed to the point that we are rolling...
|
||||
return ((distancePercentage < .1) &&
|
||||
(distance.xyMagnitude() <= targetObject.radius) &&
|
||||
(fabs(_velocity.z) <= BOUNCE_SPEED_LIMIT));
|
||||
}
|
||||
|
||||
U32BoundingBox CCollisionSphere::getBoundingBox() const {
|
||||
U32BoundingBox outBox;
|
||||
|
||||
outBox.minPoint.x = center.x - radius;
|
||||
outBox.minPoint.y = center.y - radius;
|
||||
outBox.minPoint.z = center.z - radius;
|
||||
|
||||
outBox.maxPoint.x = center.x + radius;
|
||||
outBox.maxPoint.y = center.y + radius;
|
||||
outBox.maxPoint.z = center.z + radius;
|
||||
|
||||
return outBox;
|
||||
}
|
||||
|
||||
U32BoundingBox CCollisionSphere::getBigBoundingBox() const {
|
||||
U32BoundingBox outBox;
|
||||
|
||||
float velocity = _velocity.magnitude();
|
||||
|
||||
outBox.minPoint.x = center.x - (radius + velocity);
|
||||
outBox.minPoint.y = center.y - (radius + velocity);
|
||||
outBox.minPoint.z = center.z - (radius + velocity);
|
||||
|
||||
outBox.maxPoint.x = center.x + (radius + velocity);
|
||||
outBox.maxPoint.y = center.y + (radius + velocity);
|
||||
outBox.maxPoint.z = center.z + (radius + velocity);
|
||||
|
||||
return outBox;
|
||||
}
|
||||
|
||||
void CCollisionSphere::save() {
|
||||
_positionSaved = true;
|
||||
_safetyPoint = center;
|
||||
_safetyVelocity = _velocity;
|
||||
}
|
||||
|
||||
void CCollisionSphere::restore() {
|
||||
if (_positionSaved) {
|
||||
if (_safetyVelocity.magnitude() != 0) {
|
||||
debug("CCollisionSphere::Restore(): Restoring");
|
||||
center = _safetyPoint;
|
||||
|
||||
_velocity.x = 0;
|
||||
_velocity.y = 0;
|
||||
_velocity.z = 0;
|
||||
}
|
||||
} else {
|
||||
warning("CCollisionSphere::Restore(): No save point.");
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
108
engines/scumm/he/basketball/collision/bball_collision_sphere.h
Normal file
108
engines/scumm/he/basketball/collision/bball_collision_sphere.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SPHERE_H
|
||||
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SPHERE_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
const int BOUNCE_SPEED_LIMIT = 20; // If the z-direction speed of the ball falls below this limit during a bounce, then the ball will begin to roll.
|
||||
const int ROLL_SPEED_LIMIT = 20; // If the xy-direction speed of the ball falls below this limit during a roll, then the ball will stop.
|
||||
const int ROLL_SLOWDOWN_FREQUENCY = 10; // The ball slows down every x frames while rolling.
|
||||
|
||||
class CCollisionSphere : public ICollisionObject, public U32Sphere {
|
||||
public:
|
||||
CCollisionSphere() : ICollisionObject(kSphere),
|
||||
_rollingCount(0),
|
||||
_positionSaved(false) {}
|
||||
|
||||
~CCollisionSphere() {}
|
||||
|
||||
using ICollisionObject::getObjectDistance;
|
||||
float getObjectDistance(const CCollisionBox &targetObject) const override;
|
||||
float getObjectDistance(const CCollisionCylinder &targetObject) const override;
|
||||
|
||||
using ICollisionObject::testObjectIntersection;
|
||||
bool testObjectIntersection(const CCollisionBox &targetObject, U32Distance3D *pDistance) const override;
|
||||
bool testObjectIntersection(const CCollisionCylinder &targetObject, U32Distance3D *pDistance) const override;
|
||||
|
||||
using ICollisionObject::validateCollision;
|
||||
bool validateCollision(const CCollisionBox &targetObject, U32Distance3D *pDistance) override;
|
||||
bool validateCollision(const CCollisionCylinder &targetObject, U32Distance3D *pDistance) override;
|
||||
|
||||
using ICollisionObject::backOutOfObject;
|
||||
bool backOutOfObject(const CCollisionBox &targetObject, U32Distance3D *pDistance, float *pTimeUsed) override;
|
||||
bool backOutOfObject(const CCollisionCylinder &targetObject, U32Distance3D *pDistance, float *pTimeUsed) override;
|
||||
|
||||
using ICollisionObject::nudgeObject;
|
||||
bool nudgeObject(const CCollisionBox &targetObject, U32Distance3D *pDistance, float *pTimeUsed) override;
|
||||
bool nudgeObject(const CCollisionCylinder &targetObject, U32Distance3D *pDistance, float *pTimeUsed) override;
|
||||
|
||||
void handleCollisions(CCollisionObjectVector *pCollisionVector, float *pTimeUsed, bool advanceObject) override;
|
||||
|
||||
using ICollisionObject::isOnObject;
|
||||
bool isOnObject(const CCollisionBox &targetObject, const U32Distance3D &distance) const override;
|
||||
bool isOnObject(const CCollisionCylinder &targetObject, const U32Distance3D &distance) const override;
|
||||
|
||||
U32BoundingBox getBoundingBox() const override;
|
||||
U32BoundingBox getBigBoundingBox() const override;
|
||||
|
||||
void save() override;
|
||||
void restore() override;
|
||||
|
||||
int _rollingCount;
|
||||
|
||||
|
||||
protected:
|
||||
float getDimensionDistance(const CCollisionBox &targetObject, EDimension dimension) const;
|
||||
float getDimensionDistance(const CCollisionCylinder &targetObject, EDimension dimension) const;
|
||||
|
||||
private:
|
||||
bool _positionSaved;
|
||||
U32FltPoint3D _safetyPoint;
|
||||
U32FltVector3D _safetyVelocity;
|
||||
|
||||
bool backStraightOutOfObject(const ICollisionObject &targetObject, U32Distance3D *pDistance, float *pTimeUsed);
|
||||
|
||||
using ICollisionObject::defineReflectionPlane;
|
||||
void defineReflectionPlane(const CCollisionBox &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const override;
|
||||
void defineReflectionPlane(const CCollisionCylinder &targetObject, const U32Distance3D &distance, U32Plane *collisionPlane) const override;
|
||||
|
||||
void reboundOffPlane(const U32Plane &collisionPlane, bool isOnPlane);
|
||||
|
||||
using ICollisionObject::getPenetrationTime;
|
||||
float getPenetrationTime(const CCollisionBox &targetObject, const U32Distance3D &distance, EDimension dimension) const override;
|
||||
float getPenetrationTime(const CCollisionCylinder &targetObject, const U32Distance3D &distance, EDimension dimension) const override;
|
||||
|
||||
void increaseVelocity(float minSpeed);
|
||||
};
|
||||
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SPHERE_H
|
||||
@@ -0,0 +1,73 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_box.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_node.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_tree.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
void CCollisionObjectStack::clear() {
|
||||
while (!empty()) {
|
||||
pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
int CCollisionObjectVector::getMinPoint(EDimension dimension) const {
|
||||
int min = 1000000;
|
||||
for (size_type i = 0; i < size(); i++) {
|
||||
int current = ((*this)[i])->getBoundingBox().minPoint[dimension];
|
||||
if (current < min) {
|
||||
min = current;
|
||||
}
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
int CCollisionObjectVector::getMaxPoint(EDimension dimension) const {
|
||||
int max = 0;
|
||||
for (uint i = 0; i < size(); i++) {
|
||||
int current = ((*this)[i])->getBoundingBox().minPoint[dimension];
|
||||
if (current > max) {
|
||||
max = current;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
bool CCollisionObjectVector::contains(const ICollisionObject &object) const {
|
||||
for (CCollisionObjectVector::const_iterator objectIt = begin(); objectIt != end(); ++objectIt) {
|
||||
if (object == **objectIt) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
@@ -0,0 +1,51 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_STACK_H
|
||||
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_STACK_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
|
||||
#include "common/array.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
class ICollisionObject;
|
||||
|
||||
class CCollisionObjectStack : public Common::Array<const ICollisionObject *> {
|
||||
public:
|
||||
void clear();
|
||||
};
|
||||
|
||||
class CCollisionObjectVector : public Common::Array<const ICollisionObject *> {
|
||||
public:
|
||||
int getMinPoint(EDimension dimension) const;
|
||||
int getMaxPoint(EDimension dimension) const;
|
||||
bool contains(const ICollisionObject &object) const;
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_STACK_H
|
||||
@@ -0,0 +1,716 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SUPPORT_OBJ_H
|
||||
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SUPPORT_OBJ_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "common/std/algorithm.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define BBALL_M_PI 3.14159265358979
|
||||
#define COPY_SIGN(x, y) ((x < 0) == (y < 0)) ? x : -x
|
||||
|
||||
#define MIN_GREATER_THAN_ZERO(a, b) ((a < 0) ? ((b < 0) ? ((a > b) ? a : b) : b) : ((b < 0) ? a : ((a > b) ? b : a)))
|
||||
|
||||
enum EDimension {
|
||||
X_INDEX = 0,
|
||||
Y_INDEX = 1,
|
||||
Z_INDEX = 2
|
||||
};
|
||||
|
||||
enum ERevDirection {
|
||||
kClockwise = -1,
|
||||
kNone = 0,
|
||||
kCounterClockwise = 1
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
class U32Construct2D {
|
||||
|
||||
public:
|
||||
Type x;
|
||||
Type y;
|
||||
|
||||
U32Construct2D() : x(0), y(0) {}
|
||||
U32Construct2D(Type xIn, Type yIn) : x(xIn), y(yIn) {}
|
||||
|
||||
bool operator==(const U32Construct2D<Type> &other) const {
|
||||
return ((other.x == x) && (other.y == y));
|
||||
}
|
||||
|
||||
U32Construct2D<Type> operator-(const U32Construct2D<Type> &other) const {
|
||||
U32Construct2D<Type> newConstruct;
|
||||
|
||||
newConstruct.x = x - other.x;
|
||||
newConstruct.y = y - other.y;
|
||||
|
||||
return newConstruct;
|
||||
}
|
||||
|
||||
U32Construct2D<Type> operator+(const U32Construct2D<Type> &other) const {
|
||||
U32Construct2D<Type> newConstruct;
|
||||
|
||||
newConstruct.x = x + other.x;
|
||||
newConstruct.y = y + other.y;
|
||||
|
||||
return newConstruct;
|
||||
}
|
||||
|
||||
Type operator*(const U32Construct2D<Type> &multiplier) const {
|
||||
return (x * multiplier.x + y * multiplier.y);
|
||||
}
|
||||
|
||||
Type &operator[](EDimension dimension) {
|
||||
assert(dimension <= Y_INDEX);
|
||||
return *(&x + dimension);
|
||||
}
|
||||
|
||||
const Type &operator[](EDimension dimension) const {
|
||||
assert(dimension <= Y_INDEX);
|
||||
return *(&x + dimension);
|
||||
}
|
||||
|
||||
Type magnitude(void) const {
|
||||
return (Type)(sqrt(x * x + y * y));
|
||||
}
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
class U32Construct3D {
|
||||
|
||||
public:
|
||||
Type x;
|
||||
Type y;
|
||||
Type z;
|
||||
|
||||
U32Construct3D() : x(0), y(0), z(0) {}
|
||||
U32Construct3D(Type xIn, Type yIn, Type zIn) : x(xIn), y(yIn), z(zIn) {}
|
||||
|
||||
Type magnitude(void) const {
|
||||
return (Type)(sqrt(x * x + y * y + z * z));
|
||||
}
|
||||
|
||||
Type xyMagnitude(void) const {
|
||||
return (Type)(sqrt(x * x + y * y));
|
||||
}
|
||||
|
||||
bool operator==(const U32Construct3D<Type> &other) const {
|
||||
return ((other.x == x) && (other.y == y) && (other.z == z));
|
||||
}
|
||||
|
||||
bool operator!=(const U32Construct2D<Type> &other) const {
|
||||
return ((other.x != x) || (other.y != y));
|
||||
}
|
||||
|
||||
Type &operator[](EDimension dimension) {
|
||||
assert(dimension <= Z_INDEX);
|
||||
return *(&x + dimension);
|
||||
}
|
||||
|
||||
const Type &operator[](EDimension dimension) const {
|
||||
assert(dimension <= Z_INDEX);
|
||||
return *(&x + dimension);
|
||||
}
|
||||
|
||||
U32Construct3D<Type> operator+(const U32Construct3D<Type> &other) const {
|
||||
U32Construct3D<Type> newConstruct;
|
||||
|
||||
newConstruct.x = x + other.x;
|
||||
newConstruct.y = y + other.y;
|
||||
newConstruct.z = z + other.z;
|
||||
|
||||
return newConstruct;
|
||||
}
|
||||
|
||||
Type operator*(const U32Construct3D<Type> &multiplier) const {
|
||||
return (x * multiplier.x + y * multiplier.y + z * multiplier.z);
|
||||
}
|
||||
|
||||
friend U32Construct3D<Type> operator*(const Type multiplier1[4][4], U32Construct3D<Type> multiplier2) {
|
||||
U32Construct3D<Type> newPoint;
|
||||
Type h = 0;
|
||||
int column, row;
|
||||
|
||||
for (row = X_INDEX; row <= Z_INDEX; ++row) {
|
||||
for (column = X_INDEX; column <= Z_INDEX; ++column) {
|
||||
newPoint[(EDimension)row] += multiplier1[row][column] * multiplier2[(EDimension)column];
|
||||
}
|
||||
|
||||
newPoint[(EDimension)row] += multiplier1[row][column];
|
||||
}
|
||||
|
||||
for (column = X_INDEX; column <= Z_INDEX; ++column) {
|
||||
h += multiplier1[row][column] * multiplier2[(EDimension)column];
|
||||
}
|
||||
|
||||
h += multiplier1[row][column];
|
||||
|
||||
(h == 0) ? 0 : newPoint.x /= h;
|
||||
(h == 0) ? 0 : newPoint.y /= h;
|
||||
(h == 0) ? 0 : newPoint.z /= h;
|
||||
|
||||
return newPoint;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
class U32Point3D;
|
||||
|
||||
template<class Type>
|
||||
class U32Point2D : public U32Construct2D<Type> {
|
||||
public:
|
||||
U32Point2D() : U32Construct2D<Type>() {}
|
||||
U32Point2D(Type xx, Type yy) : U32Construct2D<Type>(xx, yy) {}
|
||||
U32Point2D(const U32Construct2D<Type> &other) : U32Construct2D<Type>(other.x, other.y) {}
|
||||
U32Point2D(const U32Construct3D<Type> &other) : U32Construct2D<Type>(other.x, other.y) {} // For 3D
|
||||
|
||||
U32Point2D<Type> operator=(const U32Construct3D<Type> &other) {
|
||||
this->x = other.x;
|
||||
this->y = other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
U32Construct2D<Type> operator-(const U32Construct3D<Type> &other) const {
|
||||
U32Construct2D<Type> newPoint;
|
||||
|
||||
newPoint.x = this->x - other.x;
|
||||
newPoint.y = this->y - other.y;
|
||||
|
||||
return newPoint;
|
||||
}
|
||||
|
||||
U32Construct2D<Type> operator-(const U32Construct2D<Type> &other) const {
|
||||
U32Construct2D<Type> newPoint;
|
||||
|
||||
newPoint.x = this->x - other.x;
|
||||
newPoint.y = this->y - other.y;
|
||||
|
||||
return newPoint;
|
||||
}
|
||||
};
|
||||
|
||||
typedef U32Point2D<int> U32IntPoint2D;
|
||||
typedef U32Point2D<float> U32FltPoint2D;
|
||||
|
||||
template<class Type>
|
||||
class U32Point3D : public U32Construct3D<Type> {
|
||||
public:
|
||||
U32Point3D() : U32Construct3D<Type>() {}
|
||||
U32Point3D(Type xIn, Type yIn, Type zIn) : U32Construct3D<Type>(xIn, yIn, zIn) {}
|
||||
U32Point3D(const U32Construct3D<Type> &other) : U32Construct3D<Type>(other.x, other.y, other.z) {}
|
||||
|
||||
bool operator==(const U32Construct2D<Type> &other) const {
|
||||
return ((other.x == this->x) && (other.y == this->y));
|
||||
}
|
||||
|
||||
bool operator==(const U32Construct3D<Type> &other) const {
|
||||
return ((other.x == this->x) && (other.y == this->y) && (other.z == this->z));
|
||||
}
|
||||
|
||||
U32Construct3D<Type> operator-(const U32Construct2D<Type> &other) const {
|
||||
U32Construct3D<Type> newPoint;
|
||||
|
||||
newPoint.x = this->x - other.x;
|
||||
newPoint.y = this->y - other.y;
|
||||
newPoint.z = this->z;
|
||||
|
||||
return newPoint;
|
||||
}
|
||||
|
||||
U32Construct3D<Type> operator-(const U32Construct3D<Type> &other) const {
|
||||
U32Construct3D<Type> newPoint;
|
||||
|
||||
newPoint.x = this->x - other.x;
|
||||
newPoint.y = this->y - other.y;
|
||||
newPoint.z = this->z - other.z;
|
||||
|
||||
return newPoint;
|
||||
}
|
||||
};
|
||||
|
||||
typedef U32Point3D<int> U32IntPoint3D;
|
||||
typedef U32Point3D<float> U32FltPoint3D;
|
||||
|
||||
template<class Type>
|
||||
class U32Vector2D : public U32Construct2D<Type> {
|
||||
public:
|
||||
U32Vector2D() : U32Construct2D<Type>() {}
|
||||
U32Vector2D(Type xx, Type yy) : U32Construct2D<Type>(xx, yy) {}
|
||||
U32Vector2D(const U32Construct2D<Type> &other) : U32Construct2D<Type>(other.x, other.y) {}
|
||||
U32Vector2D(const U32Construct3D<Type> &other) : U32Construct2D<Type>(other.x, other.y) {}
|
||||
|
||||
U32Vector2D<Type> normalize() const {
|
||||
Type magnitude = this->magnitude();
|
||||
assert(magnitude > 0);
|
||||
|
||||
U32Vector2D<Type> newVector;
|
||||
newVector.x = this->x / magnitude;
|
||||
newVector.y = this->y / magnitude;
|
||||
|
||||
return newVector;
|
||||
}
|
||||
|
||||
U32Vector2D<Type> operator*(Type multiplier) const {
|
||||
U32Vector2D<Type> newVector;
|
||||
|
||||
newVector.x = multiplier * this->x;
|
||||
newVector.y = multiplier * this->y;
|
||||
|
||||
return newVector;
|
||||
}
|
||||
|
||||
Type operator*(const U32Vector2D<Type> &multiplier) const {
|
||||
return (this->x * multiplier.x + this->y * multiplier.y);
|
||||
}
|
||||
|
||||
const U32Vector2D<Type> &operator*=(Type multiplier) {
|
||||
*this = *this * multiplier;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const U32Vector2D<Type> &rotate(ERevDirection whichDirection, double radians) {
|
||||
U32Point2D<Type> newPoint;
|
||||
|
||||
if (whichDirection == kCounterClockwise) {
|
||||
newPoint.x = this->x * cos(radians) - this->y * sin(radians);
|
||||
newPoint.y = this->x * sin(radians) + this->y * cos(radians);
|
||||
} else {
|
||||
newPoint.x = this->x * cos(radians) + this->y * sin(radians);
|
||||
newPoint.y = this->y * cos(radians) - this->x * sin(radians);
|
||||
}
|
||||
|
||||
this->x = newPoint.x;
|
||||
this->y = newPoint.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
U32Construct3D<Type> cross(const U32Vector2D<Type> &otherVector) const {
|
||||
U32Construct3D<Type> newVector;
|
||||
|
||||
newVector.x = 0;
|
||||
newVector.y = 0;
|
||||
newVector.z = this->x * otherVector.y - this->y * otherVector.x;
|
||||
|
||||
return newVector;
|
||||
}
|
||||
|
||||
U32Vector2D<Type> transpose(void) const {
|
||||
U32Vector2D<Type> newVector;
|
||||
newVector.x = -this->y;
|
||||
newVector.y = this->x;
|
||||
|
||||
return newVector;
|
||||
}
|
||||
|
||||
Type distance2(const U32Vector2D<Type> &otherVector) const {
|
||||
return ((this->x - otherVector.x) * (this->x - otherVector.x) +
|
||||
(this->y - otherVector.y) * (this->y - otherVector.y));
|
||||
}
|
||||
|
||||
Type distance(const U32Vector2D<Type> &otherVector) const {
|
||||
return (Type)(sqrt((double)(distance2(otherVector))));
|
||||
}
|
||||
|
||||
ERevDirection getRevDirection(const U32Vector2D<Type> &otherVector) const {
|
||||
U32Construct3D<Type> vector3 = this->cross(otherVector);
|
||||
|
||||
if (vector3.z > 0) {
|
||||
return kCounterClockwise;
|
||||
} else if (vector3.z < 0) {
|
||||
return kClockwise;
|
||||
} else {
|
||||
return kNone;
|
||||
}
|
||||
}
|
||||
|
||||
// Project this vector onto otherVector, and return the resulting vector's magnitude.
|
||||
Type projectScalar(const U32Vector2D<Type> &otherVector) const {
|
||||
Type projectionScalar;
|
||||
|
||||
if (otherVector.magnitude() == 0) {
|
||||
projectionScalar = 0;
|
||||
} else {
|
||||
float otherMagnitude = otherVector.magnitude();
|
||||
projectionScalar = (*this * otherVector) / otherMagnitude;
|
||||
}
|
||||
|
||||
return projectionScalar;
|
||||
}
|
||||
};
|
||||
|
||||
typedef U32Vector2D<int> U32IntVector2D;
|
||||
typedef U32Vector2D<float> U32FltVector2D;
|
||||
|
||||
template<class Type>
|
||||
class U32Vector3D : public U32Construct3D<Type> {
|
||||
public:
|
||||
U32Vector3D() : U32Construct3D<Type>() {}
|
||||
U32Vector3D(Type xx, Type yy, Type zz) : U32Construct3D<Type>(xx, yy, zz) {}
|
||||
U32Vector3D(const U32Construct2D<Type> &other) : U32Construct3D<Type>(other.x, other.y, 0) {}
|
||||
U32Vector3D(const U32Construct3D<Type> &other) : U32Construct3D<Type>(other.x, other.y, other.z) {}
|
||||
|
||||
U32Vector3D<Type> operator-(const U32Construct2D<Type> &other) const {
|
||||
U32Vector3D<Type> newVector;
|
||||
|
||||
newVector.x = this->x - other.x;
|
||||
newVector.y = this->y - other.y;
|
||||
newVector.z = this->z;
|
||||
|
||||
return newVector;
|
||||
}
|
||||
|
||||
U32Vector3D<Type> operator-(const U32Construct3D<Type> &other) const {
|
||||
U32Vector3D<Type> newVector;
|
||||
|
||||
newVector.x = this->x - other.x;
|
||||
newVector.y = this->y - other.y;
|
||||
newVector.z = this->z - other.z;
|
||||
|
||||
return newVector;
|
||||
}
|
||||
|
||||
Type operator*(const U32Construct3D<Type> &multiplier) const {
|
||||
return (this->x * multiplier.x + this->y * multiplier.y + this->z * multiplier.z);
|
||||
}
|
||||
|
||||
U32Vector3D<Type> &operator+=(const U32Construct3D<Type> &adder) const {
|
||||
*this = *this + adder;
|
||||
return *this;
|
||||
}
|
||||
|
||||
U32Vector3D<Type> &operator-=(const U32Construct3D<Type> &subtractor) {
|
||||
*this = *this - subtractor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
U32Vector3D<Type> operator*(Type multiplier) const {
|
||||
U32Vector3D<Type> newVector;
|
||||
|
||||
newVector.x = multiplier * this->x;
|
||||
newVector.y = multiplier * this->y;
|
||||
newVector.z = multiplier * this->z;
|
||||
|
||||
return newVector;
|
||||
}
|
||||
|
||||
const U32Vector3D<Type> &operator*=(Type multiplier) {
|
||||
*this = *this * multiplier;
|
||||
return *this;
|
||||
}
|
||||
|
||||
U32Vector3D<Type> operator/(Type divider) const {
|
||||
U32Vector3D<Type> newVector;
|
||||
|
||||
newVector.x = (divider == 0) ? 0 : this->x / divider;
|
||||
newVector.y = (divider == 0) ? 0 : this->y / divider;
|
||||
newVector.z = (divider == 0) ? 0 : this->z / divider;
|
||||
|
||||
return newVector;
|
||||
}
|
||||
|
||||
const U32Vector3D<Type> &operator/=(Type multiplier) {
|
||||
*this = *this / multiplier;
|
||||
return *this;
|
||||
}
|
||||
|
||||
U32Vector3D<Type> cross(const U32Vector3D<Type> &otherVector) const {
|
||||
U32Vector3D<Type> newVector;
|
||||
|
||||
newVector.x = this->y * otherVector.z - this->z * otherVector.y;
|
||||
newVector.y = this->z * otherVector.x - this->x * otherVector.z;
|
||||
newVector.z = this->x * otherVector.y - this->y * otherVector.x;
|
||||
|
||||
return newVector;
|
||||
}
|
||||
|
||||
bool operator>(const U32Vector3D<Type> &otherVector) const {
|
||||
return (this->magnitude() > otherVector.magnitude());
|
||||
}
|
||||
|
||||
bool operator<(const U32Vector3D<Type> &otherVector) const {
|
||||
return (this->magnitude() < otherVector.magnitude());
|
||||
}
|
||||
|
||||
// Project this vector onto otherVector, and return the resulting vector
|
||||
U32Vector3D<Type> projectVector(const U32Vector3D<Type> &otherVector) const {
|
||||
Type projectionScalar;
|
||||
|
||||
if (otherVector.magnitude() == 0)
|
||||
projectionScalar = 0;
|
||||
else
|
||||
projectionScalar = (*this * otherVector) / (otherVector.magnitude() * otherVector.magnitude());
|
||||
|
||||
U32Vector3D<Type> newVector = otherVector * projectionScalar;
|
||||
return newVector;
|
||||
}
|
||||
|
||||
// Project this vector onto otherVector, and return the resulting vector's magnitude
|
||||
Type projectScalar(const U32Vector3D<Type> &otherVector) const {
|
||||
Type projectionScalar;
|
||||
|
||||
if (otherVector.magnitude() == 0) {
|
||||
projectionScalar = 0;
|
||||
} else {
|
||||
float otherMagnitude = otherVector.magnitude();
|
||||
projectionScalar = (*this * otherVector) / otherMagnitude;
|
||||
}
|
||||
|
||||
return projectionScalar;
|
||||
}
|
||||
|
||||
U32Vector3D<Type> normalize() const {
|
||||
Type magnitude = this->magnitude();
|
||||
assert(magnitude > 0);
|
||||
|
||||
U32Vector3D<Type> newVector;
|
||||
|
||||
if (magnitude != 0) {
|
||||
newVector.x = this->x / magnitude;
|
||||
newVector.y = this->y / magnitude;
|
||||
newVector.z = this->z / magnitude;
|
||||
}
|
||||
|
||||
return newVector;
|
||||
}
|
||||
};
|
||||
|
||||
typedef U32Vector3D<int> U32IntVector3D;
|
||||
typedef U32Vector3D<float> U32FltVector3D;
|
||||
|
||||
class U32Distance3D : public U32Construct3D<float> {
|
||||
public:
|
||||
U32Distance3D() : U32Construct3D<float>() {}
|
||||
U32Distance3D(const U32Construct2D<float> &other) : U32Construct3D<float>(other.x, other.y, 0) {}
|
||||
U32Distance3D(const U32Construct3D<float> &other) : U32Construct3D<float>(other.x, other.y, other.z) {}
|
||||
|
||||
U32Distance3D operator-(int subtractor) const {
|
||||
U32Distance3D newDistance;
|
||||
|
||||
if (magnitude() != 0) {
|
||||
newDistance.x = x - ((x * subtractor) / magnitude());
|
||||
newDistance.y = y - ((y * subtractor) / magnitude());
|
||||
newDistance.z = z - ((z * subtractor) / magnitude());
|
||||
}
|
||||
|
||||
return newDistance;
|
||||
}
|
||||
|
||||
U32Distance3D operator-=(int subtractor) {
|
||||
*this = *this - subtractor;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct U32Circle {
|
||||
|
||||
U32FltPoint2D center;
|
||||
float radius;
|
||||
};
|
||||
|
||||
struct U32Sphere {
|
||||
|
||||
U32FltPoint3D center;
|
||||
float radius;
|
||||
};
|
||||
|
||||
struct U32Cylinder : public U32Sphere {
|
||||
float height;
|
||||
};
|
||||
|
||||
struct U32BoundingBox {
|
||||
|
||||
U32IntPoint3D minPoint;
|
||||
U32IntPoint3D maxPoint;
|
||||
|
||||
void setMinPoint(int x, int y) {
|
||||
minPoint.x = x;
|
||||
minPoint.y = y;
|
||||
}
|
||||
|
||||
void setMaxPoint(int x, int y) {
|
||||
maxPoint.x = x;
|
||||
maxPoint.y = y;
|
||||
}
|
||||
|
||||
const U32IntPoint3D &getMinPoint(void) const {
|
||||
return minPoint;
|
||||
}
|
||||
|
||||
const U32IntPoint3D &getMaxPoint(void) const {
|
||||
return maxPoint;
|
||||
}
|
||||
|
||||
bool intersect(const U32BoundingBox &targetBox) const {
|
||||
return ((((minPoint.x <= targetBox.minPoint.x) &&
|
||||
(maxPoint.x >= targetBox.minPoint.x)) ||
|
||||
|
||||
((minPoint.x <= targetBox.maxPoint.x) &&
|
||||
(maxPoint.x >= targetBox.maxPoint.x)) ||
|
||||
|
||||
((targetBox.minPoint.x <= minPoint.x) &&
|
||||
(targetBox.maxPoint.x >= minPoint.x)) ||
|
||||
|
||||
((targetBox.minPoint.x <= maxPoint.x) &&
|
||||
(targetBox.maxPoint.x >= maxPoint.x)))
|
||||
|
||||
&&
|
||||
|
||||
(((minPoint.y <= targetBox.minPoint.y) &&
|
||||
(maxPoint.y >= targetBox.minPoint.y)) ||
|
||||
|
||||
((minPoint.y <= targetBox.maxPoint.y) &&
|
||||
(maxPoint.y >= targetBox.maxPoint.y)) ||
|
||||
|
||||
((targetBox.minPoint.y <= minPoint.y) &&
|
||||
(targetBox.maxPoint.y >= minPoint.y)) ||
|
||||
|
||||
((targetBox.minPoint.y <= maxPoint.y) &&
|
||||
(targetBox.maxPoint.y >= maxPoint.y))));
|
||||
}
|
||||
|
||||
const U32IntPoint3D &operator[](int point) const {
|
||||
assert(point <= 1);
|
||||
return ((point == 0) ? minPoint : maxPoint);
|
||||
}
|
||||
|
||||
U32IntPoint3D &operator[](int point) {
|
||||
assert(point <= 1);
|
||||
return ((point == 0) ? minPoint : maxPoint);
|
||||
}
|
||||
|
||||
bool isPointWithin(U32FltPoint2D point) const {
|
||||
return ((minPoint.x <= point.x) && (point.x <= maxPoint.x) &&
|
||||
(minPoint.y <= point.y) && (point.y <= maxPoint.y));
|
||||
}
|
||||
};
|
||||
|
||||
struct U32Plane {
|
||||
U32FltPoint3D point;
|
||||
U32FltVector3D normal;
|
||||
float collisionEfficiency;
|
||||
float friction;
|
||||
|
||||
// Average this plane with another plane
|
||||
U32Plane &average(const U32Plane &otherPlane) {
|
||||
point.x = (point.x + otherPlane.point.x) / 2;
|
||||
point.y = (point.y + otherPlane.point.y) / 2;
|
||||
point.z = (point.z + otherPlane.point.z) / 2;
|
||||
|
||||
normal.x = (normal.x + otherPlane.normal.x) / 2;
|
||||
normal.y = (normal.y + otherPlane.normal.y) / 2;
|
||||
normal.z = (normal.z + otherPlane.normal.z) / 2;
|
||||
|
||||
float normalMag = normal.magnitude();
|
||||
normal.x = (normalMag == 0) ? 0 : normal.x / normalMag;
|
||||
normal.y = (normalMag == 0) ? 0 : normal.y / normalMag;
|
||||
normal.z = (normalMag == 0) ? 0 : normal.z / normalMag;
|
||||
|
||||
collisionEfficiency = (collisionEfficiency + otherPlane.collisionEfficiency) / 2;
|
||||
friction = (friction + otherPlane.friction) / 2;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
point = U32FltPoint3D();
|
||||
normal = U32FltVector3D();
|
||||
collisionEfficiency = 0.0F;
|
||||
friction = 0.0F;
|
||||
}
|
||||
};
|
||||
|
||||
class U32Ray2D {
|
||||
public:
|
||||
U32FltPoint2D _origin;
|
||||
U32FltVector2D _direction;
|
||||
|
||||
bool intersection(const U32Ray2D &otherRay, U32FltPoint2D *intersection) const {
|
||||
float numerator = ((otherRay._origin - _origin) * otherRay._direction.transpose());
|
||||
float denominator = _direction * otherRay._direction.transpose();
|
||||
|
||||
if ((denominator == 0) ||
|
||||
(denominator < 0) != (numerator < 0)) {
|
||||
return false;
|
||||
} else {
|
||||
float s = numerator / denominator;
|
||||
assert(s >= 0);
|
||||
|
||||
intersection->x = _origin.x + (_direction.x * s);
|
||||
intersection->y = _origin.y + (_direction.y * s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool nearIntersection(const U32Circle &circle, U32FltPoint2D *intersection) const {
|
||||
U32FltVector2D coVector = _origin - circle.center;
|
||||
double b = _direction.normalize() * coVector;
|
||||
double c = (coVector * coVector) - (circle.radius * circle.radius);
|
||||
double d = (b * b) - c;
|
||||
|
||||
if (d < 0) {
|
||||
return false;
|
||||
} else {
|
||||
double t = -b - sqrt(d);
|
||||
|
||||
if (t < 0) {
|
||||
return false;
|
||||
} else {
|
||||
*intersection = _origin + (_direction.normalize() * t);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool farIntersection(const U32Circle &circle, U32FltPoint2D *intersection) const {
|
||||
U32FltVector2D coVector = _origin - circle.center;
|
||||
double b = _direction.normalize() * coVector;
|
||||
double c = (coVector * coVector) - (circle.radius * circle.radius);
|
||||
double d = (b * b) - c;
|
||||
|
||||
if (d < 0) {
|
||||
return false;
|
||||
} else {
|
||||
double t = -b + sqrt(d);
|
||||
|
||||
if (t < 0) {
|
||||
return false;
|
||||
} else {
|
||||
*intersection = _origin + (_direction.normalize() * t);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class U32Ray3D {
|
||||
public:
|
||||
U32FltPoint3D _origin;
|
||||
U32FltVector3D _direction;
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_SUPPORT_OBJ_H
|
||||
128
engines/scumm/he/basketball/collision/bball_collision_tree.cpp
Normal file
128
engines/scumm/he/basketball/collision/bball_collision_tree.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_sphere.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_box.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_cylinder.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_node.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_tree.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
CCollisionObjectTree::CCollisionObjectTree(const CCollisionObjectVector &inputObjects) : _maxHeight(INIT_MAX_HEIGHT),
|
||||
_maxObjectsInNode(INIT_MAX_OBJECTS),
|
||||
_root(nullptr),
|
||||
_errorFlag(false) {
|
||||
initialize(inputObjects);
|
||||
}
|
||||
|
||||
CCollisionObjectTree::~CCollisionObjectTree() {
|
||||
if (_root) {
|
||||
delete _root;
|
||||
_root = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CCollisionObjectTree::initialize(const CCollisionObjectVector &inputObjects) {
|
||||
if (_root) {
|
||||
delete _root;
|
||||
_root = nullptr;
|
||||
}
|
||||
|
||||
U32BoundingBox buildRange;
|
||||
buildRange.setMinPoint(inputObjects.getMinPoint(X_INDEX), inputObjects.getMinPoint(Y_INDEX));
|
||||
buildRange.setMaxPoint(inputObjects.getMaxPoint(X_INDEX), inputObjects.getMaxPoint(Y_INDEX));
|
||||
_root = buildSelectionStructure(inputObjects, 0, buildRange);
|
||||
}
|
||||
|
||||
void CCollisionObjectTree::selectObjectsInBound(const U32BoundingBox &bound, CCollisionObjectVector *targetVector) {
|
||||
_root->searchTree(bound, targetVector);
|
||||
|
||||
if (targetVector->size() <= 0) {
|
||||
warning("CCollisionObjectTree::selectObjectsInBound(): (targetVector->size() <= 0) Something went really wrong with a collision, ignore and U32 will attempt to correct.");
|
||||
_errorFlag = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Here we make sure that we don't have any duplicate objects in our target stack...
|
||||
Std::sort(targetVector->begin(), targetVector->end());
|
||||
|
||||
CCollisionObjectVector::iterator newEnd = Std::unique(targetVector->begin(), targetVector->end());
|
||||
targetVector->erase(newEnd, targetVector->end());
|
||||
}
|
||||
|
||||
bool CCollisionObjectTree::checkErrors() {
|
||||
if (_errorFlag) {
|
||||
_errorFlag = false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CCollisionNode *CCollisionObjectTree::buildSelectionStructure(const CCollisionObjectVector &inputObjects, int currentLevel, const U32BoundingBox &nodeRange) {
|
||||
// Create a new node, containing all of the input points...
|
||||
CCollisionNode *newNode = new CCollisionNode(inputObjects);
|
||||
newNode->_quadrant = nodeRange;
|
||||
|
||||
// See if we are at the final level, or if we have reached our target occupancy...
|
||||
if ((currentLevel == _maxHeight) ||
|
||||
(inputObjects.size() <= _maxObjectsInNode)) {
|
||||
newNode->_isExternal = true;
|
||||
} else {
|
||||
newNode->_isExternal = false;
|
||||
|
||||
// Otherwise, break the inputPoints into 4 new point lists...
|
||||
CCollisionObjectVector newList[NUM_CHILDREN_NODES];
|
||||
U32BoundingBox newRange[NUM_CHILDREN_NODES];
|
||||
int childID;
|
||||
|
||||
for (childID = 0; childID < NUM_CHILDREN_NODES; childID++) {
|
||||
newRange[childID] = CCollisionNode::getChildQuadrant(nodeRange, (EChildID)childID);
|
||||
}
|
||||
|
||||
// Go through each point in the list...
|
||||
for (size_t i = 0; i < inputObjects.size(); i++) {
|
||||
const ICollisionObject *currentObject = inputObjects[i];
|
||||
|
||||
// Figure out which child each point belongs to...
|
||||
for (childID = 0; childID < NUM_CHILDREN_NODES; ++childID) {
|
||||
if (newRange[childID].intersect(currentObject->getBoundingBox())) {
|
||||
newList[childID].push_back(currentObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make recursive calls...
|
||||
for (childID = 0; childID < NUM_CHILDREN_NODES; ++childID) {
|
||||
newNode->_child[childID] = buildSelectionStructure(newList[childID],
|
||||
currentLevel + 1,
|
||||
newRange[childID]);
|
||||
}
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
64
engines/scumm/he/basketball/collision/bball_collision_tree.h
Normal file
64
engines/scumm/he/basketball/collision/bball_collision_tree.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_TREE_H
|
||||
#define SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_TREE_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_node.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define INIT_MAX_HEIGHT 10
|
||||
#define INIT_MAX_OBJECTS 5
|
||||
|
||||
class CCollisionObjectTree {
|
||||
public:
|
||||
CCollisionObjectTree() : _maxHeight(INIT_MAX_HEIGHT),
|
||||
_maxObjectsInNode(INIT_MAX_OBJECTS),
|
||||
_root(nullptr),
|
||||
_errorFlag(false) {}
|
||||
|
||||
CCollisionObjectTree(const CCollisionObjectVector &inputObjects);
|
||||
~CCollisionObjectTree();
|
||||
|
||||
void initialize(const CCollisionObjectVector &inputObjects);
|
||||
void selectObjectsInBound(const U32BoundingBox &bound, CCollisionObjectVector *targetVector);
|
||||
|
||||
bool checkErrors();
|
||||
|
||||
private:
|
||||
CCollisionNode *buildSelectionStructure(const CCollisionObjectVector &inputObjects, int currentLevel, const U32BoundingBox &nodeRange);
|
||||
|
||||
int _maxHeight;
|
||||
size_t _maxObjectsInNode;
|
||||
CCollisionNode *_root;
|
||||
bool _errorFlag;
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COLLISION_BBALL_COLLISION_TREE_H
|
||||
74
engines/scumm/he/basketball/court.cpp
Normal file
74
engines/scumm/he/basketball/court.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
|
||||
#include "scumm/he/basketball/basketball.h"
|
||||
#include "scumm/he/basketball/court.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
int CBBallCourt::getPlayerIndex(int playerID) {
|
||||
assert((FIRST_PLAYER <= playerID) && (playerID <= LAST_PLAYER));
|
||||
|
||||
Common::Array<CCollisionPlayer> *playerList = getPlayerListPtr(playerID);
|
||||
for (size_t i = 0; i < playerList->size(); i++) {
|
||||
if ((*playerList)[i]._objectID == playerID) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
warning("CBBallCourt::getPlayerIndex(): Tried to find a player in the player list that was not there.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
CCollisionPlayer *CBBallCourt::getPlayerPtr(int playerID) {
|
||||
assert((FIRST_PLAYER <= playerID) && (playerID <= LAST_PLAYER));
|
||||
|
||||
Common::Array<CCollisionPlayer> *playerList = getPlayerListPtr(playerID);
|
||||
|
||||
size_t listSize = playerList->size();
|
||||
for (size_t i = 0; i < listSize; i++) {
|
||||
if ((*playerList)[i]._objectID == playerID) {
|
||||
return &((*playerList)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
warning("CBBallCourt::getPlayerPtr(): Tried to find a player in the player list that was not there.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CCollisionBasketball *CBBallCourt::getBallPtr(int ballID) {
|
||||
CCollisionBasketball *sourceBall;
|
||||
|
||||
if (ballID == _basketBall._objectID) {
|
||||
sourceBall = &_basketBall;
|
||||
} else if (ballID == _virtualBall._objectID) {
|
||||
sourceBall = &_virtualBall;
|
||||
} else {
|
||||
warning("CBBallCourt::getBallPtr(): Invalid ball ID passed to u32_userDetectBallCollision.");
|
||||
sourceBall = &_basketBall;
|
||||
}
|
||||
|
||||
return sourceBall;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
112
engines/scumm/he/basketball/court.h
Normal file
112
engines/scumm/he/basketball/court.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_COURT_H
|
||||
#define SCUMM_HE_BASKETBALL_COURT_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_object.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_box.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_basketball.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_player.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_stack.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_tree.h"
|
||||
|
||||
#include "scumm/he/logic_he.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
// COURT DEFINES
|
||||
|
||||
#define MAX_PLAYERS_ON_TEAM 5
|
||||
|
||||
#define NO_PLAYER -1
|
||||
#define FIRST_PLAYER 0
|
||||
#define AWAY_PLAYER_1 5
|
||||
#define LAST_PLAYER 9
|
||||
|
||||
#define TEAM_HOME 0
|
||||
#define TEAM_AWAY 1
|
||||
|
||||
#define SHOT_SPOT_RADIUS 13
|
||||
|
||||
#define NO_COURT 0
|
||||
#define COURT_DOBBAGUCHI 1
|
||||
#define COURT_SMITH_BROS 2
|
||||
#define COURT_SANDY_FLATS 3
|
||||
#define COURT_QUEENS 4
|
||||
#define COURT_PLAYGROUND 5
|
||||
#define COURT_SCHEFFLER 6
|
||||
#define COURT_POLK 7
|
||||
#define COURT_MCMILLAN 8
|
||||
#define COURT_CROWN_HILL 9
|
||||
#define COURT_MEMORIAL 10
|
||||
#define COURT_TECH_STATE 11
|
||||
#define COURT_HUMONGOUS 12
|
||||
#define COURT_MOON 13
|
||||
#define COURT_BARN 14
|
||||
#define COURT_COUNT 15
|
||||
|
||||
class CBBallCourt {
|
||||
public:
|
||||
CBBallCourt() {
|
||||
_objectCount = 0;
|
||||
_backboardIndex[0] = 0;
|
||||
_backboardIndex[1] = 0;
|
||||
}
|
||||
|
||||
~CBBallCourt() = default;
|
||||
|
||||
int getPlayerIndex(int playerID);
|
||||
CCollisionPlayer *getPlayerPtr(int playerID);
|
||||
CCollisionBasketball *getBallPtr(int ballID);
|
||||
|
||||
Common::Array<CCollisionPlayer> *getPlayerListPtr(int i) {
|
||||
return (i < AWAY_PLAYER_1) ? &_homePlayerList : &_awayPlayerList;
|
||||
}
|
||||
|
||||
Common::Array<CCollisionPlayer> *getOpponentListPtr(int i) {
|
||||
return (i < AWAY_PLAYER_1) ? &_awayPlayerList : &_homePlayerList;
|
||||
}
|
||||
|
||||
Common::String _name;
|
||||
|
||||
CCollisionBasketball _basketBall;
|
||||
CCollisionBasketball _virtualBall;
|
||||
|
||||
Common::Array<CCollisionBox> _objectList;
|
||||
CCollisionObjectTree _objectTree;
|
||||
Common::Array<CCollisionPlayer> _homePlayerList;
|
||||
Common::Array<CCollisionPlayer> _awayPlayerList;
|
||||
int _objectCount;
|
||||
int _backboardIndex[2];
|
||||
U32Sphere _shotSpot[2] = {};
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_COURT_H
|
||||
141
engines/scumm/he/basketball/cursor.cpp
Normal file
141
engines/scumm/he/basketball/cursor.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/basketball/basketball.h"
|
||||
#include "scumm/he/logic_he.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define STICKY_CURSOR_VALUE 2
|
||||
|
||||
static void checkCursorBounds(const Common::Point &oldCursorPos, Common::Point *cursorPos) {
|
||||
Common::Rect windowRect(0, 0, 640, 480);
|
||||
|
||||
// Make sure the cursor wasn't pushed out of the window...
|
||||
if ((cursorPos->x < (windowRect.left + 1)) && (oldCursorPos.x > windowRect.left)) {
|
||||
cursorPos->x = (windowRect.left + 1);
|
||||
}
|
||||
|
||||
if ((cursorPos->x > (windowRect.right - 1)) && (oldCursorPos.x < windowRect.right)) {
|
||||
cursorPos->x = (windowRect.right - 1);
|
||||
}
|
||||
|
||||
if ((cursorPos->y < (windowRect.top + 1)) && (oldCursorPos.y > windowRect.top)) {
|
||||
cursorPos->y = (windowRect.top + 1);
|
||||
}
|
||||
|
||||
if ((cursorPos->y > (windowRect.bottom - 1)) && (oldCursorPos.y < windowRect.bottom)) {
|
||||
cursorPos->y = (windowRect.bottom - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int LogicHEBasketball::u32_userUpdateCursorPos(int xScrollVal, int yScrollVal) {
|
||||
int xChange = 0;
|
||||
int yChange = 0;
|
||||
|
||||
Common::Point currentCursorPos = _vm->_mouse;
|
||||
|
||||
// Update that position due to any camera scrolling that happened this frame...
|
||||
Common::Point newCursorPos;
|
||||
newCursorPos.x = currentCursorPos.x - xScrollVal;
|
||||
newCursorPos.y = currentCursorPos.y - yScrollVal;
|
||||
|
||||
// Make sure the cursor wasn't pushed out of the window...
|
||||
checkCursorBounds(currentCursorPos, &newCursorPos);
|
||||
|
||||
// Update the cursor position...
|
||||
_vm->_mouse = newCursorPos;
|
||||
|
||||
// Calculate how much the cursor actually changed this frame...
|
||||
xChange = newCursorPos.x - currentCursorPos.x;
|
||||
yChange = newCursorPos.y - currentCursorPos.y;
|
||||
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, 1);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, xChange);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_C, yChange);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userMakeCursorSticky(int lastCursorX, int lastCursorY) {
|
||||
int success = 0;
|
||||
|
||||
int xChange = 0;
|
||||
int yChange = 0;
|
||||
|
||||
Common::Point currentCursorPos = _vm->_mouse;
|
||||
|
||||
Common::Point newCursorPos;
|
||||
|
||||
// Update that position due to any camera scrolling that happened this frame...
|
||||
newCursorPos.x = lastCursorX + ((currentCursorPos.x - lastCursorX) / STICKY_CURSOR_VALUE);
|
||||
newCursorPos.y = lastCursorY + ((currentCursorPos.y - lastCursorY) / STICKY_CURSOR_VALUE);
|
||||
|
||||
// Make sure the cursor wasn't pushed out of the window...
|
||||
checkCursorBounds(currentCursorPos, &newCursorPos);
|
||||
|
||||
// Update the cursor position...
|
||||
_vm->_mouse = newCursorPos;
|
||||
|
||||
// Calculate how much the cursor actually changed this frame...
|
||||
xChange = newCursorPos.x - currentCursorPos.x;
|
||||
yChange = newCursorPos.y - currentCursorPos.y;
|
||||
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, success);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, xChange);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_C, yChange);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userCursorTrackMovingObject(int xChange, int yChange) {
|
||||
Common::Point currentCursorPos = _vm->_mouse;
|
||||
Common::Point newCursorPos;
|
||||
|
||||
// Update that position due to any camera scrolling that happened this frame...
|
||||
newCursorPos.x = currentCursorPos.x + xChange;
|
||||
newCursorPos.y = currentCursorPos.y + yChange;
|
||||
|
||||
// Make sure the cursor wasn't pushed out of the window...
|
||||
checkCursorBounds(currentCursorPos, &newCursorPos);
|
||||
|
||||
// Update the cursor position...
|
||||
_vm->_mouse = newCursorPos;
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, 1);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, xChange);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_C, yChange);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userGetCursorPos() {
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_mouse.x);
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_mouse.y);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
254
engines/scumm/he/basketball/geo_translation.cpp
Normal file
254
engines/scumm/he/basketball/geo_translation.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/logic_he.h"
|
||||
|
||||
#include "scumm/he/basketball/geo_translations.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
int LogicHEBasketball::u32_userInitScreenTranslations() {
|
||||
// Find the angle between the left and bottom baseline in the court image...
|
||||
_courtAngle = atan(TRANSLATED_MAX_Y / (double)TRANSLATED_MAX_START_X);
|
||||
|
||||
// The relationship between the location in the game world and the location in pixels
|
||||
// from the bottom of the court can be described by the parametric equation:
|
||||
//
|
||||
// y = [(x-c)^(1/2) - c^(1/2)] / a^(1/2)
|
||||
//
|
||||
// Here, x is worldPoint.y and y is pixelsFromBottom. This is where we calculate the constant
|
||||
// coefficients a, b, and c.
|
||||
_yTranslationA = (float)((((MAX_WORLD_Y / 2.0) * TRANSLATED_MAX_Y) - (MAX_WORLD_Y * (float)TRANSLATED_MID_Y)) / ((TRANSLATED_MID_Y * TRANSLATED_MID_Y * (float)TRANSLATED_MAX_Y) - (TRANSLATED_MAX_Y * TRANSLATED_MAX_Y * (float)TRANSLATED_MID_Y)));
|
||||
assert(_yTranslationA != 0);
|
||||
|
||||
_yTranslationB = (MAX_WORLD_Y / (float)TRANSLATED_MAX_Y) - (_yTranslationA * TRANSLATED_MAX_Y);
|
||||
_yTranslationC = (_yTranslationB * _yTranslationB) / (4.0 * _yTranslationA);
|
||||
assert(_yTranslationC != 0);
|
||||
|
||||
// The relationship between the location in pixels from the bottom of the court and
|
||||
// the location in world points can be described by the parametric equation:
|
||||
//
|
||||
// y = ax^2 + bx +c
|
||||
//
|
||||
// Here, x is pixelsFromBottom and y is worldPoint.y. This is where we calculate the constant
|
||||
// coefficients a, b, and c.
|
||||
_yRevTranslationA = (((MAX_WORLD_Y / (float)2) * TRANSLATED_MAX_Y) - (MAX_WORLD_Y * (float)TRANSLATED_MID_Y)) / ((TRANSLATED_MID_Y * TRANSLATED_MID_Y * (float)TRANSLATED_MAX_Y) - (TRANSLATED_MAX_Y * TRANSLATED_MAX_Y * (float)TRANSLATED_MID_Y));
|
||||
_yRevTranslationB = (MAX_WORLD_Y / (float)TRANSLATED_MAX_Y) - (_yRevTranslationA * TRANSLATED_MAX_Y);
|
||||
_yRevTranslationC = 0;
|
||||
|
||||
// As you move up the screen, the number of world points per screen pixel increases
|
||||
// parametrically. Vice versa for moving down the screen. It may be desirable to
|
||||
// have a top and bottom cutoff point. So there will be a point above the court where
|
||||
// the point to pixel ratio stops increasing and a point below the court where the point
|
||||
// to pixel ratio stops decreasing. Here, the corresponding world points are calculated.
|
||||
_topScalingPointCutoff = _vm->_basketball->u32FloatToInt(
|
||||
_yRevTranslationA * TOP_SCALING_PIXEL_CUTOFF * TOP_SCALING_PIXEL_CUTOFF +
|
||||
_yRevTranslationB * TOP_SCALING_PIXEL_CUTOFF +
|
||||
_yRevTranslationC);
|
||||
|
||||
_bottomScalingPointCutoff = _vm->_basketball->u32FloatToInt(
|
||||
_yRevTranslationA * BOTTOM_SCALING_PIXEL_CUTOFF * BOTTOM_SCALING_PIXEL_CUTOFF +
|
||||
_yRevTranslationB * BOTTOM_SCALING_PIXEL_CUTOFF +
|
||||
_yRevTranslationC);
|
||||
|
||||
assert(_topScalingPointCutoff >= MAX_WORLD_Y);
|
||||
assert(_bottomScalingPointCutoff <= 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static U32FltPoint2D worldToScreenTranslation(const U32FltPoint3D &worldPoint, LogicHEBasketball *logic) {
|
||||
U32FltPoint2D screenPoint; // The point on the screen that corresponds to worldPoint
|
||||
float courtWidth; // The width of the court in pixels at the at the current y location
|
||||
float xOffset; // The number of pixels from the left side of the screen to the court at the current y location
|
||||
|
||||
float pixelsFromBottom;
|
||||
float zToYOffset; // Given the current world z coordinate, how many pixels in the y direction should the object be moved
|
||||
float a, c; // The constant coefficients for the parametric equation which describes the relation between world y coordinates and screen y coordinates
|
||||
float slope; // The derivative of the above mentioned equation
|
||||
|
||||
assert(MAX_WORLD_X != 0);
|
||||
assert(MAX_WORLD_Y != 0);
|
||||
assert(TRANSLATED_MAX_START_X != 0);
|
||||
|
||||
// Let's find y...
|
||||
|
||||
a = logic->_yTranslationA;
|
||||
c = logic->_yTranslationC;
|
||||
|
||||
// Normally, the game world coordinates compress as you move further up the screen.
|
||||
// This adds to the illusion of depth perception. Sometimes it may be desirable to stop
|
||||
// this compression after a certain point on the screen. This 'if block' handles that
|
||||
// case...
|
||||
if (worldPoint.y < logic->_bottomScalingPointCutoff) {
|
||||
slope = 1 / (2 * sqrt(a * logic->_bottomScalingPointCutoff + a * c));
|
||||
pixelsFromBottom = slope * (worldPoint.y - logic->_bottomScalingPointCutoff) + BOTTOM_SCALING_PIXEL_CUTOFF;
|
||||
} else if (worldPoint.y < logic->_topScalingPointCutoff) {
|
||||
slope = 1 / (2 * sqrt(a * worldPoint.y + a * c));
|
||||
pixelsFromBottom = (sqrt(worldPoint.y + c) - sqrt(c)) / sqrt(a);
|
||||
} else {
|
||||
slope = 1 / (2 * sqrt(a * logic->_topScalingPointCutoff + a * c));
|
||||
pixelsFromBottom = slope * (worldPoint.y - logic->_topScalingPointCutoff) + TOP_SCALING_PIXEL_CUTOFF;
|
||||
}
|
||||
|
||||
screenPoint.y = BB_SCREEN_SIZE_Y - COURT_Y_OFFSET - pixelsFromBottom;
|
||||
|
||||
// Let's find x...
|
||||
|
||||
if (pixelsFromBottom < BOTTOM_SCALING_PIXEL_CUTOFF) {
|
||||
courtWidth = TRANSLATED_NEAR_MAX_X - (2.0 * (BOTTOM_SCALING_PIXEL_CUTOFF / tan(logic->_courtAngle)));
|
||||
xOffset = (tan((BBALL_M_PI / 2.0) - logic->_courtAngle) * BOTTOM_SCALING_PIXEL_CUTOFF) + COURT_X_OFFSET;
|
||||
} else if (pixelsFromBottom < TOP_SCALING_PIXEL_CUTOFF) {
|
||||
courtWidth = (TRANSLATED_NEAR_MAX_X - (2.0 * (pixelsFromBottom / tan(logic->_courtAngle))));
|
||||
xOffset = (tan((BBALL_M_PI / 2.0) - logic->_courtAngle) * pixelsFromBottom) + COURT_X_OFFSET;
|
||||
} else {
|
||||
// Find the width of the court in pixels at the current y coordinate...
|
||||
courtWidth = TRANSLATED_NEAR_MAX_X - (2.0 * (TOP_SCALING_PIXEL_CUTOFF / tan(logic->_courtAngle)));
|
||||
|
||||
// Find the number of pixels beetween the left side of the screen and the beginning of the court at the current y coordinate...
|
||||
xOffset = tan(((BBALL_M_PI / 2.0) - logic->_courtAngle) * TOP_SCALING_PIXEL_CUTOFF) + COURT_X_OFFSET;
|
||||
}
|
||||
|
||||
// Find the screen x based on the world x and y...
|
||||
screenPoint.x = (worldPoint.x * courtWidth / MAX_WORLD_X) + xOffset;
|
||||
|
||||
// Now factor in world z to the screen y coordinate...
|
||||
zToYOffset = (courtWidth / MAX_WORLD_X) * worldPoint.z;
|
||||
screenPoint.y -= zToYOffset;
|
||||
|
||||
return screenPoint;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userWorldToScreenTranslation(const U32FltPoint3D &worldPoint) {
|
||||
U32FltPoint2D screenPoint = worldToScreenTranslation(worldPoint, this);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(screenPoint.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(screenPoint.y));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userScreenToWorldTranslation(const U32FltPoint2D &screenPoint) {
|
||||
U32FltPoint2D worldPoint; // The point in the game world that corresponds to screenPoint
|
||||
float courtWidth; // The width of the court in pixels at the at the current y location
|
||||
float xOffset; // The number of pixels from the left side of the screen to the court at the current y location
|
||||
|
||||
float pixelsFromBottom;
|
||||
float a, b, c; // The constant coefficients for the parametric equation which describes the relation between screen y coordinates and world y coordinates
|
||||
float slope; // The derivative of the above mentioned equation
|
||||
|
||||
assert(TRANSLATED_MAX_START_X != 0);
|
||||
assert(TRANSLATED_NEAR_MAX_X != 0);
|
||||
assert(TRANSLATED_FAR_MAX_X != 0);
|
||||
assert(TRANSLATED_MAX_Y != 0);
|
||||
|
||||
// Let's find y...
|
||||
|
||||
a = _yRevTranslationA;
|
||||
b = _yRevTranslationB;
|
||||
c = _yRevTranslationC;
|
||||
|
||||
pixelsFromBottom = BB_SCREEN_SIZE_Y - COURT_Y_OFFSET - screenPoint.y;
|
||||
|
||||
// Normally, the game world coordinates compress as you move further up the screen.
|
||||
// This adds to the illusion of depth perception. Sometimes it may be desirable to stop
|
||||
// this compression after a certain point on the screen. This 'if block' handles that
|
||||
// case...
|
||||
if (pixelsFromBottom < BOTTOM_SCALING_PIXEL_CUTOFF) {
|
||||
slope = (2 * a * BOTTOM_SCALING_PIXEL_CUTOFF + b);
|
||||
worldPoint.y = slope * (pixelsFromBottom - BOTTOM_SCALING_PIXEL_CUTOFF) + _bottomScalingPointCutoff;
|
||||
} else if (pixelsFromBottom < TOP_SCALING_PIXEL_CUTOFF) {
|
||||
worldPoint.y = a * pixelsFromBottom * pixelsFromBottom + b * pixelsFromBottom + c;
|
||||
} else {
|
||||
slope = (2 * a * TOP_SCALING_PIXEL_CUTOFF + b);
|
||||
worldPoint.y = slope * (pixelsFromBottom - TOP_SCALING_PIXEL_CUTOFF) + _topScalingPointCutoff;
|
||||
}
|
||||
|
||||
// -Let's find x...
|
||||
|
||||
if (pixelsFromBottom < BOTTOM_SCALING_PIXEL_CUTOFF) {
|
||||
courtWidth = TRANSLATED_NEAR_MAX_X - (2.0 * (BOTTOM_SCALING_PIXEL_CUTOFF / tan(_courtAngle)));
|
||||
xOffset = (tan((BBALL_M_PI / 2.0) - _courtAngle) * BOTTOM_SCALING_PIXEL_CUTOFF) + COURT_X_OFFSET;
|
||||
} else if (pixelsFromBottom < TOP_SCALING_PIXEL_CUTOFF) {
|
||||
// Find the width of the court in pixels at the current y coordinate...
|
||||
courtWidth = TRANSLATED_NEAR_MAX_X - (2.0 * (pixelsFromBottom / tan(_courtAngle)));
|
||||
|
||||
// Find the number of pixels beetween the left side of the screen and the beginning of the court at the current y coordinate...
|
||||
xOffset = (tan((BBALL_M_PI / 2.0) - _courtAngle) * pixelsFromBottom) + COURT_X_OFFSET;
|
||||
} else {
|
||||
// Find the width of the court in pixels at the current y coordinate...
|
||||
courtWidth = TRANSLATED_NEAR_MAX_X - (2.0 * (TOP_SCALING_PIXEL_CUTOFF / tan(_courtAngle)));
|
||||
|
||||
// Find the number of pixels beetween the left side of the screen and the beginning of the court at the current y coordinate...
|
||||
xOffset = (tan((BBALL_M_PI / 2.0) - _courtAngle) * TOP_SCALING_PIXEL_CUTOFF) + COURT_X_OFFSET;
|
||||
}
|
||||
|
||||
// Find the world x based on the screen x and y...
|
||||
assert(courtWidth != 0);
|
||||
worldPoint.x = (screenPoint.x - xOffset) * MAX_WORLD_X / courtWidth;
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(worldPoint.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(worldPoint.y));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userGetCourtDimensions() {
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(MAX_WORLD_X));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(MAX_WORLD_Y));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_C, _vm->_basketball->u32FloatToInt(BASKET_X));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_D, _vm->_basketball->u32FloatToInt(BASKET_Y));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_E, _vm->_basketball->u32FloatToInt(BASKET_Z));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userComputePointsForPixels(int pixels, int screenYPos) {
|
||||
float points;
|
||||
float pixelsFromBottom;
|
||||
float courtWidth;
|
||||
float courtAngle;
|
||||
|
||||
courtAngle = atan(TRANSLATED_MAX_Y / (double)TRANSLATED_MAX_START_X);
|
||||
pixelsFromBottom = BB_SCREEN_SIZE_Y - COURT_Y_OFFSET - screenYPos;
|
||||
|
||||
if (pixelsFromBottom < 0) {
|
||||
courtWidth = TRANSLATED_NEAR_MAX_X;
|
||||
// FIXME: Remove duplicated condition branch?
|
||||
#if 0
|
||||
} else if (pixelsFromBottom < TRANSLATED_MAX_Y) {
|
||||
// Find the width of the court in pixels at the current y coordinate...
|
||||
courtWidth = TRANSLATED_NEAR_MAX_X - (2.0 * (pixelsFromBottom / tan(courtAngle)));
|
||||
#endif
|
||||
} else {
|
||||
// Find the width of the court in pixels at the current y coordinate...
|
||||
courtWidth = TRANSLATED_NEAR_MAX_X - (2.0 * (pixelsFromBottom / tan(courtAngle)));
|
||||
}
|
||||
|
||||
points = (MAX_WORLD_X / courtWidth) * pixels;
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(points));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
67
engines/scumm/he/basketball/geo_translations.h
Normal file
67
engines/scumm/he/basketball/geo_translations.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_GEO_TRANSLATIONS_H
|
||||
#define SCUMM_HE_BASKETBALL_GEO_TRANSLATIONS_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/logic_he.h"
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define BB_SCREEN_SIZE_Y 640 // Please note, this is intentional! It shouldn't be 480!
|
||||
|
||||
#define COURT_X_OFFSET 18 // Pixels from left of screen to beginning of court
|
||||
#define COURT_Y_OFFSET 33 // Pixels from bottom of screen to beginning of court
|
||||
|
||||
#define TRANSLATED_MAX_Y 302 // Pixels from bottom of court to top of court
|
||||
#define TRANSLATED_MID_Y 186 // Pixels from bottom of the court to center court
|
||||
#define TRANSLATED_DIAGONAL_Y 431 // Pixel length of the baseline
|
||||
#define TRANSLATED_MAX_START_X 308 // This is how far over x = 0 is pushed when y = MAX_WORLD_Y
|
||||
#define TRANSLATED_FAR_MAX_X 950 // Length of the far side of field ( world_y = MAX_WORLD_Y) when translated
|
||||
#define TRANSLATED_NEAR_MAX_X 1564 // Length of near side of field (world_y = MAX_WORLD_Y when translated
|
||||
|
||||
// Length and width of the court in game world units
|
||||
#define WORLD_UNIT_MULTIPLIER 160
|
||||
#define MAX_WORLD_X (75 * WORLD_UNIT_MULTIPLIER)
|
||||
#define MAX_WORLD_Y (50 * WORLD_UNIT_MULTIPLIER)
|
||||
|
||||
// Coordinates of the center of the hoop
|
||||
#define BASKET_PUSH_BACK_DIST (0.5 * WORLD_UNIT_MULTIPLIER)
|
||||
|
||||
#define BASKET_X (int)((5.25 * WORLD_UNIT_MULTIPLIER) - BASKET_PUSH_BACK_DIST)
|
||||
#define BASKET_Y (25 * WORLD_UNIT_MULTIPLIER)
|
||||
#define BASKET_Z (10 * WORLD_UNIT_MULTIPLIER)
|
||||
|
||||
// The screen coordinate that sandwich where on the screen scaling occurs;
|
||||
// these coordinates are given in pixels from the bottom of the court
|
||||
#define TOP_SCALING_PIXEL_CUTOFF (1000 - COURT_Y_OFFSET)
|
||||
#define BOTTOM_SCALING_PIXEL_CUTOFF (0 - COURT_Y_OFFSET)
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_GEO_TRANSLATIONS_H
|
||||
423
engines/scumm/he/basketball/obstacle_avoidance.cpp
Normal file
423
engines/scumm/he/basketball/obstacle_avoidance.cpp
Normal file
@@ -0,0 +1,423 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/basketball/basketball.h"
|
||||
#include "scumm/he/basketball/court.h"
|
||||
#include "scumm/he/basketball/obstacle_avoidance.h"
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/stack.h"
|
||||
#include "common/queue.h"
|
||||
#include "common/std/set.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
float Basketball::getAvoidanceDistance(const U32Circle &playerMarker, const CCollisionPlayer &obstacle) {
|
||||
// Figure out how close we want to buzz the obstacle...
|
||||
float passByDistance = (playerMarker.radius + obstacle.radius + OBSTACLE_AVOIDANCE_DISTANCE);
|
||||
|
||||
// Figure out how close we are to the obstacle...
|
||||
float currentDistance = (playerMarker.center - obstacle.center).magnitude();
|
||||
|
||||
// Use the smaller of the two...
|
||||
float avoidanceDistance = MIN(currentDistance, passByDistance);
|
||||
return avoidanceDistance;
|
||||
}
|
||||
|
||||
CCollisionPlayer *Basketball::detectObstacle(const U32Circle &playerMarker,
|
||||
int playerID,
|
||||
const U32FltPoint2D &targetLocation,
|
||||
bool targetIsObstacle,
|
||||
U32FltPoint2D *intersection,
|
||||
CBBallCourt *court) {
|
||||
// Create a ray whose origin is at the player's center, and whose direction
|
||||
// is the player's target vector...
|
||||
U32Ray2D poRay;
|
||||
poRay._origin = playerMarker.center;
|
||||
poRay._direction = (targetLocation - poRay._origin);
|
||||
|
||||
// Cycle through all potential obstacles and see which obstacle is closest...
|
||||
CCollisionPlayer *finalObstacle = nullptr;
|
||||
float minDistance = (float)0x7FFFFFFF;
|
||||
|
||||
for (int i = 0; i <= LAST_PLAYER; ++i) {
|
||||
// Get a pointer to the current obstacle...
|
||||
CCollisionPlayer *currentObstacle = court->getPlayerPtr(i);
|
||||
|
||||
// Make sure we are not checking ourselves or a bench player...
|
||||
if ((currentObstacle->_objectID != playerID) &&
|
||||
(currentObstacle->_playerIsInGame)) {
|
||||
U32Circle obstacleMarker;
|
||||
obstacleMarker.center = currentObstacle->center;
|
||||
obstacleMarker.radius = getAvoidanceDistance(playerMarker, *currentObstacle);
|
||||
|
||||
if (poRay.nearIntersection(obstacleMarker, intersection)) {
|
||||
float obstacleDist = (*intersection - playerMarker.center).magnitude();
|
||||
|
||||
float alertDistance = MIN(AVOIDANCE_LOOK_AHEAD_DISTANCE, poRay._direction.magnitude());
|
||||
|
||||
// See if this obstacle is in our way...
|
||||
if (obstacleDist < alertDistance) {
|
||||
// See if the target is within the obstacle...
|
||||
float otDist = (targetLocation - currentObstacle->center).magnitude();
|
||||
if ((otDist > obstacleMarker.radius) || targetIsObstacle) {
|
||||
// See if this obstacle is the closest one yet...
|
||||
if (obstacleDist < minDistance) {
|
||||
finalObstacle = currentObstacle;
|
||||
minDistance = obstacleDist;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return finalObstacle;
|
||||
}
|
||||
|
||||
bool Basketball::avoidObstacle(const U32Circle &playerMarker, const U32FltPoint2D &targetLocation, const CCollisionPlayer &obstacle, ERevDirection whichDirection, U32FltPoint2D *newTarget) {
|
||||
double sinTheta;
|
||||
double theta;
|
||||
|
||||
// Get a vector from the player center to the obstacle center...
|
||||
U32FltVector2D poVector = obstacle.center - playerMarker.center;
|
||||
|
||||
// Get a vector from the target center to the obstacle center...
|
||||
U32FltVector2D toVector = obstacle.center - targetLocation;
|
||||
|
||||
// Figure out how close we want to buzz the obstacle...
|
||||
float avoidanceDistance = getAvoidanceDistance(playerMarker, obstacle);
|
||||
avoidanceDistance += AVOIDANCE_SAFETY_DISTANCE;
|
||||
|
||||
// Figure out if we are avoinding the obstacle in the clockwise or
|
||||
// counter-clockwise direction...
|
||||
if (whichDirection == kNone) {
|
||||
whichDirection = getAvoidanceDirection(playerMarker, targetLocation, obstacle);
|
||||
}
|
||||
|
||||
// Figure out how many radians of roatation away from the center of the
|
||||
// obstacle (using our center as the origin) we need to aim for in order to
|
||||
// perfectly buzz the obstacle...
|
||||
if (poVector.magnitude() == 0) {
|
||||
sinTheta = 0;
|
||||
} else {
|
||||
sinTheta = avoidanceDistance / poVector.magnitude();
|
||||
if ((sinTheta < -MAX_AVOIDANCE_ANGLE_SIN) || (MAX_AVOIDANCE_ANGLE_SIN < sinTheta)) {
|
||||
sinTheta = MAX_AVOIDANCE_ANGLE_SIN;
|
||||
}
|
||||
}
|
||||
|
||||
theta = asin(sinTheta);
|
||||
|
||||
// Create a vector that points in the direction we must now travel...
|
||||
poVector.rotate(whichDirection, theta);
|
||||
|
||||
// This vector will take us as close as we want to go to the obstacle, but
|
||||
// we don't know how far in that direction we need to travel. To get to the,
|
||||
// target we need to buzz the obstacle once, continue on a little bit, then
|
||||
// turn and buzz the obstacle again. Right now we are going to calculate
|
||||
// that second buzz path...
|
||||
|
||||
// We are caluclating from the target to the obstacle, so swap the direction...
|
||||
whichDirection = (whichDirection == kClockwise) ? kCounterClockwise : kClockwise;
|
||||
|
||||
if (toVector.magnitude() == 0) {
|
||||
sinTheta = 0;
|
||||
} else {
|
||||
sinTheta = avoidanceDistance / toVector.magnitude();
|
||||
if (sinTheta < -MAX_AVOIDANCE_ANGLE_SIN) {
|
||||
sinTheta = -MAX_AVOIDANCE_ANGLE_SIN;
|
||||
} else if (sinTheta > MAX_AVOIDANCE_ANGLE_SIN) {
|
||||
sinTheta = MAX_AVOIDANCE_ANGLE_SIN;
|
||||
}
|
||||
}
|
||||
|
||||
theta = asin(sinTheta);
|
||||
|
||||
// Create a vector that points in the direction we must travel after our
|
||||
// initial pass-by of the target...
|
||||
toVector.rotate(whichDirection, theta);
|
||||
|
||||
// Where the player and target vector's meet is where we should aim for...
|
||||
U32Ray2D poRay;
|
||||
poRay._origin = playerMarker.center;
|
||||
poRay._direction = poVector;
|
||||
|
||||
U32Ray2D toRay;
|
||||
toRay._origin = targetLocation;
|
||||
toRay._direction = toVector;
|
||||
|
||||
return poRay.intersection(toRay, newTarget);
|
||||
}
|
||||
|
||||
ERevDirection Basketball::getAvoidanceDirection(const U32Circle &playerMarker, const U32FltPoint2D &targetLocation, const CCollisionPlayer &obstacle) {
|
||||
U32FltVector3D obstacleVector = obstacle.center - playerMarker.center;
|
||||
U32FltVector3D targetVector = targetLocation - playerMarker.center;
|
||||
U32FltVector3D crossVector = obstacleVector.cross(targetVector);
|
||||
|
||||
return (crossVector.z > 0) ? kCounterClockwise : kClockwise;
|
||||
}
|
||||
|
||||
bool Basketball::getPathDistance(U32Circle *playerMarker, int playerID, Common::Stack<U32FltPoint2D> *targetStack, ERevDirection lastTurn, float *pathDistance, Common::Queue<U32FltPoint2D> *wayPointQueue, Std::set<int> *obstacleSet, CBBallCourt *court) {
|
||||
U32FltPoint2D intersection;
|
||||
|
||||
// See if we're going for the final target...
|
||||
bool shootingForFinalTarget = (targetStack->size() == 1);
|
||||
|
||||
U32FltPoint2D ¤tTarget = targetStack->top();
|
||||
|
||||
// See if there is an obstacle between us and the target...
|
||||
CCollisionPlayer *obstacle = detectObstacle(*playerMarker, playerID, currentTarget, !shootingForFinalTarget, &intersection, court);
|
||||
if (obstacle) {
|
||||
// Make sure we haven't run into this obstacle already...
|
||||
Std::set<int>::const_iterator obstacleIt = obstacleSet->find(obstacle->_objectID);
|
||||
if (obstacleIt != obstacleSet->end()) {
|
||||
if (targetStack->size() != 1) {
|
||||
targetStack->pop();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Recursively call getPathDistance for both the left and right paths
|
||||
// around the current obstacle...
|
||||
ERevDirection turnDirection = getBestPath(*playerMarker, playerID, targetStack,
|
||||
obstacle, lastTurn, pathDistance,
|
||||
wayPointQueue, obstacleSet, court);
|
||||
|
||||
if (turnDirection == kNone) {
|
||||
if (targetStack->size() != 1) {
|
||||
targetStack->pop();
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// Get the distance between the player and the target...
|
||||
float targetDistance = (currentTarget - playerMarker->center).magnitude();
|
||||
|
||||
// Add that distance to the current total for this path...
|
||||
*pathDistance += targetDistance;
|
||||
|
||||
// Advance the player to the target...
|
||||
playerMarker->center = currentTarget;
|
||||
|
||||
// See if this gets us to the final destination...
|
||||
if (shootingForFinalTarget) {
|
||||
return true;
|
||||
} else {
|
||||
wayPointQueue->push(currentTarget);
|
||||
targetStack->pop();
|
||||
|
||||
// Keep on going for the final target...
|
||||
return getPathDistance(playerMarker, playerID, targetStack,
|
||||
kNone, pathDistance, wayPointQueue,
|
||||
obstacleSet, court);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Basketball::pushTargetOutOfObstacle(const U32Circle &playerMarker, const CCollisionPlayer &obstacle, Common::Stack<U32FltPoint2D> *targetStack) {
|
||||
// Get the effective radius of the obstacle...
|
||||
float avoidanceDistance = getAvoidanceDistance(playerMarker, obstacle);
|
||||
|
||||
// See if the target is within that radius...
|
||||
if ((targetStack->top() - obstacle.center).magnitude() < avoidanceDistance) {
|
||||
// Make sure this isn't the final target...
|
||||
if (targetStack->size() == 1) {
|
||||
warning("Basketball::pushTargetOutOfObstacle(): Should not be calling this function on the final target");
|
||||
}
|
||||
|
||||
// Make a ray from the player to the target...
|
||||
U32Ray2D playerRay;
|
||||
playerRay._origin = playerMarker.center;
|
||||
playerRay._direction = targetStack->top() - playerMarker.center;
|
||||
|
||||
// Make a circle around the obstacle...
|
||||
U32Circle obstacleCircle;
|
||||
obstacleCircle.center = obstacle.center;
|
||||
obstacleCircle.radius = avoidanceDistance;
|
||||
|
||||
// Find the farthest intersection of the ray and the circle...
|
||||
U32FltPoint2D newTarget;
|
||||
if (playerRay.farIntersection(obstacleCircle, &newTarget)) {
|
||||
targetStack->pop();
|
||||
targetStack->push(newTarget);
|
||||
} else {
|
||||
warning("Basketball::pushTargetOutOfObstacle(): Unable to intersect the player ray with the obstacle circle");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ERevDirection Basketball::getBestPath(const U32Circle &playerMarker, int playerID, Common::Stack<U32FltPoint2D> *targetStack, CCollisionPlayer *obstacle,
|
||||
ERevDirection lastTurn, float *distance, Common::Queue<U32FltPoint2D> *wayPointQueue, Std::set<int> *obstacleSet, CBBallCourt *court) {
|
||||
U32Circle tempLocation;
|
||||
|
||||
float leftDistance = 0;
|
||||
float rightDistance = 0;
|
||||
|
||||
bool leftPath = false;
|
||||
bool rightPath = false;
|
||||
|
||||
Common::Queue<U32FltPoint2D> leftWayPointQueue;
|
||||
Common::Queue<U32FltPoint2D> rightWayPointQueue;
|
||||
|
||||
// Add this obstacle to the obstacle set...
|
||||
obstacleSet->insert(obstacle->_objectID);
|
||||
|
||||
// Clear out any unnecessary interim targets...
|
||||
while (targetStack->size() != 1) {
|
||||
targetStack->pop();
|
||||
}
|
||||
|
||||
// Get the avoidance path to the left...
|
||||
if (kClockwise != lastTurn) {
|
||||
U32FltPoint2D leftTarget;
|
||||
|
||||
if (avoidObstacle(playerMarker, targetStack->top(), *obstacle, kCounterClockwise, &leftTarget)) {
|
||||
tempLocation = playerMarker;
|
||||
|
||||
targetStack->push(leftTarget);
|
||||
|
||||
leftWayPointQueue = *wayPointQueue;
|
||||
|
||||
leftPath = getPathDistance(&tempLocation, playerID, targetStack,
|
||||
kCounterClockwise, &leftDistance, &leftWayPointQueue,
|
||||
obstacleSet, court);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the avoidance path to the right...
|
||||
if (kCounterClockwise != lastTurn) {
|
||||
U32FltPoint2D rightTarget;
|
||||
|
||||
if (avoidObstacle(playerMarker, targetStack->top(),
|
||||
*obstacle, kClockwise, &rightTarget)) {
|
||||
tempLocation = playerMarker;
|
||||
|
||||
targetStack->push(rightTarget);
|
||||
|
||||
rightWayPointQueue = *wayPointQueue;
|
||||
|
||||
rightPath = getPathDistance(&tempLocation, playerID, targetStack,
|
||||
kClockwise, &rightDistance, &rightWayPointQueue,
|
||||
obstacleSet, court);
|
||||
}
|
||||
}
|
||||
|
||||
// See which path is better
|
||||
if (leftPath && rightPath) {
|
||||
*distance = MIN(leftDistance, rightDistance);
|
||||
if (*distance == leftDistance) {
|
||||
*wayPointQueue = Common::move(leftWayPointQueue);
|
||||
return kCounterClockwise;
|
||||
} else {
|
||||
*wayPointQueue = Common::move(rightWayPointQueue);
|
||||
return kClockwise;
|
||||
}
|
||||
} else if (leftPath && !rightPath) {
|
||||
*distance = leftDistance;
|
||||
*wayPointQueue = Common::move(leftWayPointQueue);
|
||||
return kCounterClockwise;
|
||||
} else if (!leftPath && rightPath) {
|
||||
*distance = rightDistance;
|
||||
*wayPointQueue = Common::move(rightWayPointQueue);
|
||||
return kClockwise;
|
||||
} else {
|
||||
*distance = 0;
|
||||
return kNone;
|
||||
}
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userGetAvoidancePath(int playerID, const U32FltPoint2D &targetLocation, EAvoidanceType type) {
|
||||
U32FltPoint2D newTarget;
|
||||
U32FltPoint2D intersection;
|
||||
|
||||
// Get a pointer to the source player...
|
||||
CCollisionPlayer *player = _vm->_basketball->_court->getPlayerPtr(playerID);
|
||||
|
||||
// Make sure the player isn't already at its target...
|
||||
if (player->center == targetLocation) {
|
||||
newTarget = targetLocation;
|
||||
} else {
|
||||
// Extract the player's current location...
|
||||
U32Circle playerMarker;
|
||||
playerMarker.center = player->center;
|
||||
playerMarker.radius = player->radius;
|
||||
|
||||
// See if an obstacle was found...
|
||||
CCollisionPlayer *obstacle = _vm->_basketball->detectObstacle(playerMarker, player->_objectID,
|
||||
targetLocation, false, &intersection,
|
||||
_vm->_basketball->_court);
|
||||
|
||||
if (obstacle) {
|
||||
if (type == kMultipleObject) {
|
||||
Common::Queue<U32FltPoint2D> wayPointQueue;
|
||||
Common::Stack<U32FltPoint2D> targetStack;
|
||||
Std::set<int> obstacleSet;
|
||||
|
||||
targetStack.push(targetLocation);
|
||||
|
||||
float pathDistance;
|
||||
|
||||
ERevDirection turnDirection = _vm->_basketball->getBestPath(playerMarker, player->_objectID, &targetStack,
|
||||
obstacle, kNone, &pathDistance, &wayPointQueue, &obstacleSet,
|
||||
_vm->_basketball->_court);
|
||||
|
||||
targetStack.pop();
|
||||
|
||||
if (!targetStack.empty()) {
|
||||
warning("LogicHEBasketball::u32_userGetAvoidancePath(): It doesn't look like we calculated things out to the final target.");
|
||||
}
|
||||
|
||||
if (wayPointQueue.empty()) {
|
||||
assert(turnDirection == kNone);
|
||||
|
||||
// We were unable to find a valid path to the target,
|
||||
// so treat this like a single obstacle...
|
||||
if (!_vm->_basketball->avoidObstacle(playerMarker, targetLocation, *obstacle, kNone, &newTarget)) {
|
||||
warning("LogicHEBasketball::u32_userGetAvoidancePath(): Unable to go around the primary obstacle");
|
||||
newTarget = targetLocation;
|
||||
}
|
||||
} else {
|
||||
newTarget = wayPointQueue.front();
|
||||
}
|
||||
} else {
|
||||
if (!_vm->_basketball->avoidObstacle(playerMarker, targetLocation, *obstacle, kNone, &newTarget)) {
|
||||
warning("LogicHEBasketball::u32_userGetAvoidancePath(): Unable to go around the primary obstacle");
|
||||
newTarget = targetLocation;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newTarget = targetLocation;
|
||||
}
|
||||
}
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(newTarget.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(newTarget.y));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
46
engines/scumm/he/basketball/obstacle_avoidance.h
Normal file
46
engines/scumm/he/basketball/obstacle_avoidance.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_OBSTACLE_AVOIDANCE_H
|
||||
#define SCUMM_HE_BASKETBALL_OBSTACLE_AVOIDANCE_H
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define AVOIDANCE_LOOK_AHEAD_DISTANCE 4000.0F
|
||||
#define OBSTACLE_AVOIDANCE_DISTANCE 75
|
||||
#define AVOIDANCE_SAFETY_DISTANCE 1
|
||||
#define MAX_AVOIDANCE_ANGLE_SIN 1.0F
|
||||
|
||||
enum EAvoidanceType {
|
||||
kSingleObject = 0,
|
||||
kMultipleObject = 1
|
||||
};
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_OBSTACLE_AVOIDANCE_H
|
||||
320
engines/scumm/he/basketball/passing.cpp
Normal file
320
engines/scumm/he/basketball/passing.cpp
Normal file
@@ -0,0 +1,320 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/basketball/court.h"
|
||||
#include "scumm/he/basketball/passing.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
static float getBallImpactTime(CCollisionSphere *ball, int gravity, int height) {
|
||||
// Solve the equation:
|
||||
//
|
||||
// z + vz * t - 0.5 * g * t * t = height
|
||||
//
|
||||
// to find out how long before the ball hits the ground...
|
||||
float a = -.5 * gravity;
|
||||
float b = ball->_velocity.z;
|
||||
float c = ball->center.z - ball->radius - height;
|
||||
|
||||
double tFinal;
|
||||
if (((b * b) < (4 * a * c)) || (a == 0)) {
|
||||
tFinal = 0;
|
||||
} else {
|
||||
// See how long before the ball hits the ground...
|
||||
tFinal = (-b - sqrt(b * b - 4 * a * c)) / (2 * a);
|
||||
tFinal = MAX(0.0, tFinal);
|
||||
}
|
||||
|
||||
return tFinal;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userComputeAngleOfPass(int velocity, int hDist, int vDist, int gravity) {
|
||||
assert(hDist > 0);
|
||||
|
||||
double theta = _vm->_basketball->getLaunchAngle(velocity, hDist, vDist, gravity);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32DoubleToInt(theta));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userComputeAngleOfBouncePass(int velocity, int hDist, int currentZ, int destZ, int gravity) {
|
||||
double theta;
|
||||
int vDist;
|
||||
|
||||
assert(hDist > 0);
|
||||
|
||||
// Aim the ball at the floor 2/3 the distance between you and your target...
|
||||
hDist = (hDist * 2) / 3;
|
||||
vDist = 0 - currentZ;
|
||||
theta = _vm->_basketball->getLaunchAngle(velocity, hDist, vDist, gravity);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32DoubleToInt(theta));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userHitMovingTarget(U32FltPoint2D sourcePlayer, U32FltPoint2D targetPlayer, U32FltVector2D targetVelocity, int passSpeed) {
|
||||
// Calculate the xy speed of the pass. To do this, we need to estimate
|
||||
// the elevation angle of the pass. This is because the actual angle
|
||||
// will be calculated based on the target location, which is what we
|
||||
// are currently getting...
|
||||
float xyPassSpeed = passSpeed * cos((PASS_ANGLE * BBALL_M_PI) / 180);
|
||||
|
||||
// The distance between the target player at future time t and and the
|
||||
// passing player is equal to the pass speed times t. Solve for t...
|
||||
float a = (targetVelocity.x * targetVelocity.x) +
|
||||
(targetVelocity.y * targetVelocity.y) -
|
||||
(xyPassSpeed * xyPassSpeed);
|
||||
|
||||
float b = (2 * targetPlayer.x * targetVelocity.x) +
|
||||
(2 * targetPlayer.y * targetVelocity.y) -
|
||||
(2 * sourcePlayer.x * targetVelocity.x) -
|
||||
(2 * sourcePlayer.y * targetVelocity.y);
|
||||
|
||||
float c = (targetPlayer.x * targetPlayer.x) +
|
||||
(targetPlayer.y * targetPlayer.y) +
|
||||
(sourcePlayer.x * sourcePlayer.x) +
|
||||
(sourcePlayer.y * sourcePlayer.y) -
|
||||
(2 * targetPlayer.x * sourcePlayer.x) -
|
||||
(2 * targetPlayer.y * sourcePlayer.y);
|
||||
|
||||
// Now we have two answer candidates. We want the smallest of the two that is
|
||||
// greater than 0...
|
||||
double tFinal;
|
||||
if (((b * b) < (4 * a * c)) || (a == 0)) {
|
||||
tFinal = 0.0;
|
||||
} else {
|
||||
double t1 = (-b + sqrt(b * b - 4 * a * c)) / (2 * a);
|
||||
double t2 = (-b - sqrt(b * b - 4 * a * c)) / (2 * a);
|
||||
tFinal = MIN_GREATER_THAN_ZERO(t1, t2);
|
||||
tFinal -= BALL_LEAD_TIME; // Put the player at the target spot a few frames
|
||||
// before the ball to give them a chance to get ready
|
||||
// to catch it...
|
||||
tFinal = MAX(0.0, tFinal);
|
||||
}
|
||||
|
||||
assert(tFinal < 50.0);
|
||||
|
||||
U32FltPoint2D targetPoint;
|
||||
targetPoint.x = targetPlayer.x + (targetVelocity.x * tFinal);
|
||||
targetPoint.y = targetPlayer.y + (targetVelocity.y * tFinal);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(targetPoint.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(targetPoint.y));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_C, _vm->_basketball->u32DoubleToInt(tFinal));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userGetPassTarget(int playerID, const U32FltVector3D &aimVector) {
|
||||
U32Ray3D passerRay;
|
||||
|
||||
// Get our target candidates...
|
||||
Common::Array<CCollisionPlayer> *targetList = (_vm->_basketball->_court->getPlayerListPtr(playerID));
|
||||
|
||||
// Get the passer...
|
||||
CCollisionPlayer *passer = _vm->_basketball->_court->getPlayerPtr(playerID);
|
||||
|
||||
// Set up a ray from the passer, pointing in the direction of the aim vector...
|
||||
passerRay._origin = passer->center;
|
||||
passerRay._direction = aimVector.normalize() * MAX_PASSING_DIST;
|
||||
|
||||
// Get the distance from the passers aim vector to each of the remaining target
|
||||
// candidates...
|
||||
int passTargetID = NO_PLAYER;
|
||||
float leastDist = MAX_PASSING_DIST;
|
||||
|
||||
for (size_t i = 0; i < targetList->size(); ++i) {
|
||||
// Get the current target candidate...
|
||||
CCollisionPlayer *target = &(*targetList)[i];
|
||||
|
||||
// Make sure the target is in the game...
|
||||
if (target->_playerIsInGame) {
|
||||
// Make sure that the passing player is not a target candidate...
|
||||
if (passer->_objectID != target->_objectID) {
|
||||
// Point-line distance formula.
|
||||
U32FltPoint3D *targetCenter = &target->center;
|
||||
|
||||
float u = (((targetCenter->x - passerRay._origin.x) * passerRay._direction.x) +
|
||||
((targetCenter->y - passerRay._origin.y) * passerRay._direction.y)) /
|
||||
(passerRay._direction.magnitude() * passerRay._direction.magnitude());
|
||||
|
||||
if (u >= 0) {
|
||||
U32FltVector3D distance;
|
||||
distance.x = targetCenter->x - (passerRay._origin.x + (u * passerRay._direction.x));
|
||||
distance.y = targetCenter->y - (passerRay._origin.y + (u * passerRay._direction.y));
|
||||
float totalDist = distance.magnitude();
|
||||
if (totalDist < leastDist) {
|
||||
leastDist = totalDist;
|
||||
passTargetID = target->_objectID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, passTargetID);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userDetectPassBlocker(int playerID, const U32FltPoint3D &targetPoint) {
|
||||
int blockerPresent = 0;
|
||||
|
||||
// Get our blocker candidates....
|
||||
Common::Array<CCollisionPlayer> *targetList = (_vm->_basketball->_court->getOpponentListPtr(playerID));
|
||||
|
||||
// Get the passer and catcher...
|
||||
CCollisionPlayer *passer = _vm->_basketball->_court->getPlayerPtr(playerID);
|
||||
|
||||
// Set up a ray from the passer, pointing in the direction of the aim vector...
|
||||
U32FltVector2D passVector = targetPoint - passer->center;
|
||||
|
||||
// Get the distance from the passers aim vector to each of the remaining target
|
||||
// candidates...
|
||||
for (size_t i = 0; i < targetList->size(); ++i) {
|
||||
CCollisionPlayer *blocker = &(*targetList)[i];
|
||||
|
||||
if (blocker->_playerIsInGame) {
|
||||
// --- Ray -> Circle intersection test ---
|
||||
// Get a vector from the passer to the potential blocker...
|
||||
U32FltVector2D enemyVector = blocker->center - passer->center;
|
||||
|
||||
// Project that vector onto the pass vector
|
||||
float enemyDistance = enemyVector.projectScalar(passVector);
|
||||
|
||||
// Test to see if the blocker is behind the pass or behind the pass target...
|
||||
float maxBlockerDistance = passVector.magnitude();
|
||||
if ((0 > enemyDistance) || (enemyDistance > maxBlockerDistance)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the distance between the blocker and the passVector...
|
||||
float mSquared = (enemyVector.magnitude() * enemyVector.magnitude()) -
|
||||
(enemyDistance * enemyDistance);
|
||||
|
||||
// If that distance is less than the blocker's radius, we are done...
|
||||
if (mSquared <= ((blocker->radius + _vm->_basketball->_court->_basketBall.radius) * (blocker->radius + _vm->_basketball->_court->_basketBall.radius))) {
|
||||
blockerPresent = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, blockerPresent);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userGetBallIntercept(int playerID, int ballID, int playerSpeed, int gravity) {
|
||||
double tFinal = 0.0;
|
||||
|
||||
CCollisionSphere *ball = _vm->_basketball->_court->getBallPtr(ballID);
|
||||
CCollisionPlayer *player = _vm->_basketball->_court->getPlayerPtr(playerID);
|
||||
|
||||
assert(!ball->_ignore);
|
||||
|
||||
U32Circle playerMarker;
|
||||
playerMarker.center = player->center;
|
||||
playerMarker.radius = player->radius + ball->radius;
|
||||
|
||||
U32Ray2D playerRay;
|
||||
playerRay._origin = player->center;
|
||||
playerRay._direction = player->_velocity;
|
||||
|
||||
U32Ray2D ballRay;
|
||||
ballRay._origin = ball->center;
|
||||
ballRay._direction = ball->_velocity;
|
||||
|
||||
// See if the ball is standing still...
|
||||
if (ballRay._direction.magnitude() == 0) {
|
||||
tFinal = 0.0;
|
||||
} else {
|
||||
// See when the ball is going to fall to the player's height...
|
||||
float tFall = getBallImpactTime(ball, gravity, (player->height / 2));
|
||||
|
||||
// See if the ball is headed straight for us...
|
||||
U32FltPoint2D intersection;
|
||||
if (ballRay.nearIntersection(playerMarker, &intersection)) {
|
||||
// Get the time till the ball reaches the player...
|
||||
float tPlayerImpact = (ball->center - player->center).xyMagnitude() / ball->_velocity.xyMagnitude();
|
||||
|
||||
// Decide if it's best to stay put, or run back where the ball will fall to...
|
||||
tFinal = MAX(tPlayerImpact, tFall);
|
||||
} else {
|
||||
// The distance between the target player at future time t and and the
|
||||
// ball is equal to the playerSpeed times t. Solve for t...
|
||||
float a = (ball->_velocity.x * ball->_velocity.x) +
|
||||
(ball->_velocity.y * ball->_velocity.y) -
|
||||
(playerSpeed * playerSpeed);
|
||||
|
||||
float b = (2 * ball->center.x * ball->_velocity.x) +
|
||||
(2 * ball->center.y * ball->_velocity.y) -
|
||||
(2 * player->center.x * ball->_velocity.x) -
|
||||
(2 * player->center.y * ball->_velocity.y);
|
||||
|
||||
float c = (ball->center.x * ball->center.x) +
|
||||
(ball->center.y * ball->center.y) +
|
||||
(player->center.x * player->center.x) +
|
||||
(player->center.y * player->center.y) -
|
||||
(2 * ball->center.x * player->center.x) -
|
||||
(2 * ball->center.y * player->center.y);
|
||||
|
||||
if (((b * b) < (4 * a * c)) || (a == 0)) {
|
||||
// Now see if we can get away with just going the way we were...
|
||||
if (playerRay.intersection(ballRay, &intersection)) {
|
||||
tFinal = (ball->center - intersection).xyMagnitude() / ball->_velocity.xyMagnitude();
|
||||
}
|
||||
} else {
|
||||
// Find the closest place we could intercept the ball...
|
||||
tFinal = (-b - sqrt(b * b - 4 * a * c)) / (2 * a);
|
||||
if (tFinal < 0) {
|
||||
tFinal = (-b + sqrt(b * b - 4 * a * c)) / (2 * a);
|
||||
}
|
||||
|
||||
// See if the ball will come down low enough to catch by that time...
|
||||
tFinal = MAX((double)tFall, tFinal);
|
||||
}
|
||||
|
||||
// Now see if we're just better off just going the way we were...
|
||||
if (playerRay.intersection(ballRay, &intersection)) {
|
||||
float tFutureImpact = (ball->center - intersection).xyMagnitude() / ball->_velocity.xyMagnitude();
|
||||
tFinal = MAX((double)tFutureImpact, tFinal);
|
||||
}
|
||||
}
|
||||
|
||||
// Now see if we're better off just chasing the ball...
|
||||
tFinal = MAX(0.0, tFinal);
|
||||
}
|
||||
|
||||
U32FltPoint2D targetPoint;
|
||||
targetPoint.x = ball->center.x + (ball->_velocity.x * tFinal);
|
||||
targetPoint.y = ball->center.y + (ball->_velocity.y * tFinal);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(targetPoint.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(targetPoint.y));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
43
engines/scumm/he/basketball/passing.h
Normal file
43
engines/scumm/he/basketball/passing.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_PASSING_H
|
||||
#define SCUMM_HE_BASKETBALL_PASSING_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/logic_he.h"
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define BALL_LEAD_TIME 2
|
||||
#define MAX_PASSING_DIST 15000
|
||||
#define MAX_BLOCKER_DISTANCE (6 * WORLD_UNIT_MULTIPLIER)
|
||||
#define PASS_ANGLE 30
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_PASSING_H
|
||||
181
engines/scumm/he/basketball/shooting.cpp
Normal file
181
engines/scumm/he/basketball/shooting.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision.h"
|
||||
#include "scumm/he/basketball/court.h"
|
||||
#include "scumm/he/basketball/geo_translations.h"
|
||||
#include "scumm/he/basketball/shooting.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
int LogicHEBasketball::u32_userComputeInitialShotVelocity(int theta, int hDist, int vDist, int gravity) {
|
||||
double velocity;
|
||||
double trajectoryAngle;
|
||||
double targetAngle;
|
||||
|
||||
assert(gravity > 0);
|
||||
|
||||
if ((hDist == 0) && (vDist == 0)) {
|
||||
velocity = 0;
|
||||
} else {
|
||||
trajectoryAngle = (theta * BBALL_M_PI) / 180;
|
||||
|
||||
// Find the angle between the horizon and the line between the source and the target...
|
||||
targetAngle = atan2(vDist, hDist);
|
||||
|
||||
// If the shot is impossible, then return a 0 for velocity, otherwise calculate the
|
||||
// required velocity...
|
||||
if ((theta == 90) && (hDist == 0)) {
|
||||
velocity = sqrt(abs(vDist) * 2 * gravity);
|
||||
} else if (((targetAngle >= 0) && (targetAngle < (BBALL_M_PI / 2))) &&
|
||||
((trajectoryAngle <= targetAngle) || (trajectoryAngle >= (BBALL_M_PI / 2)))) {
|
||||
velocity = 0;
|
||||
} else if (((targetAngle >= (BBALL_M_PI / 2) && (targetAngle < BBALL_M_PI))) &&
|
||||
((trajectoryAngle >= targetAngle) || (trajectoryAngle <= (BBALL_M_PI / 2)))) {
|
||||
velocity = 0;
|
||||
} else if (((targetAngle >= -BBALL_M_PI && (targetAngle < -(BBALL_M_PI / 2)))) &&
|
||||
((trajectoryAngle >= targetAngle) || (trajectoryAngle <= (BBALL_M_PI / 2)))) {
|
||||
velocity = 0;
|
||||
} else if (((targetAngle >= -(BBALL_M_PI / 2) && (targetAngle < 0))) &&
|
||||
((trajectoryAngle <= targetAngle) || (trajectoryAngle >= (BBALL_M_PI / 2)))) {
|
||||
velocity = 0;
|
||||
} else {
|
||||
float numerator = gravity * hDist * hDist;
|
||||
float denominator = (2 * vDist * cos(trajectoryAngle) * cos(trajectoryAngle)) +
|
||||
(2 * hDist * sin(trajectoryAngle) * cos(trajectoryAngle));
|
||||
|
||||
assert((numerator / denominator) >= 0);
|
||||
|
||||
if ((numerator / denominator) < 0) {
|
||||
velocity = 0;
|
||||
} else {
|
||||
velocity = sqrt(numerator / denominator);
|
||||
}
|
||||
|
||||
// Hack, because this is off somehow, or because to go in the hoop,
|
||||
// the ball should hit a little in front...
|
||||
velocity -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32DoubleToInt(velocity));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static double getShotAngle(int hDist, int vDist) {
|
||||
double degrees;
|
||||
float hUnits;
|
||||
float a, b, c;
|
||||
|
||||
assert(hDist >= 0);
|
||||
|
||||
if (vDist == 0) {
|
||||
if (hDist == 0)
|
||||
degrees = MAX_SHOT_ANGLE;
|
||||
else
|
||||
degrees = MIN_SHOT_ANGLE;
|
||||
} else {
|
||||
hUnits = hDist / -(float)vDist;
|
||||
|
||||
a = (float)((2.0 - 4.0) / ((TEN_FOOT_SHOT_ANGLE - MIN_SHOT_ANGLE) * 4.0 * 2.0 - 4.0 * (MAX_SHOT_ANGLE - MIN_SHOT_ANGLE)));
|
||||
b = a / ((MAX_SHOT_ANGLE - MIN_SHOT_ANGLE) * a - 1.0);
|
||||
c = MIN_SHOT_ANGLE;
|
||||
|
||||
degrees = 1.0 / (a * (hUnits + 1.0) * (hUnits + 1.0)) + 1.0 / (b * (hUnits + 1.0)) + c;
|
||||
}
|
||||
|
||||
return degrees;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userComputeAngleOfShot(int hDist, int vDist) {
|
||||
double degrees;
|
||||
|
||||
degrees = getShotAngle(hDist, vDist);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32DoubleToInt(degrees));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userComputeBankShotTarget(U32FltPoint3D basketLoc, int ballRadius) {
|
||||
U32FltPoint3D targetPoint;
|
||||
float backboardDist;
|
||||
CCollisionBox *backboard;
|
||||
|
||||
if (basketLoc.x < (MAX_WORLD_X / 2)) {
|
||||
// Left basket...
|
||||
backboard = &(_vm->_basketball->_court->_objectList[_vm->_basketball->_court->_backboardIndex[LEFT_BASKET]]);
|
||||
backboardDist = basketLoc.x - backboard->maxPoint.x;
|
||||
} else {
|
||||
// Right basket...
|
||||
backboard = &(_vm->_basketball->_court->_objectList[_vm->_basketball->_court->_backboardIndex[RIGHT_BASKET]]);
|
||||
backboardDist = basketLoc.x - backboard->minPoint.x;
|
||||
}
|
||||
|
||||
targetPoint.x = basketLoc.x - (2 * backboardDist);
|
||||
targetPoint.y = basketLoc.y;
|
||||
targetPoint.z = basketLoc.z + ballRadius;
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(targetPoint.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(targetPoint.y));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_C, _vm->_basketball->u32FloatToInt(targetPoint.z));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userComputeSwooshTarget(const U32FltPoint3D &basketLoc, int ballRadius) {
|
||||
U32FltPoint3D targetPoint;
|
||||
|
||||
targetPoint.x = basketLoc.x;
|
||||
targetPoint.y = basketLoc.y;
|
||||
targetPoint.z = basketLoc.z + ballRadius;
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(targetPoint.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(targetPoint.y));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_C, _vm->_basketball->u32FloatToInt(targetPoint.z));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userDetectShotMade(const U32Sphere &basketball, const U32IntVector3D &ballVector, int gravity, int whichBasket) {
|
||||
int shotWasMade = 0;
|
||||
U32Distance3D distance;
|
||||
|
||||
distance.x = basketball.center.x - _vm->_basketball->_court->_shotSpot[whichBasket].center.x;
|
||||
distance.y = basketball.center.y - _vm->_basketball->_court->_shotSpot[whichBasket].center.y;
|
||||
distance.z = basketball.center.z - _vm->_basketball->_court->_shotSpot[whichBasket].center.z;
|
||||
|
||||
if (distance.magnitude() <= (_vm->_basketball->_court->_shotSpot[whichBasket].radius + basketball.radius)) {
|
||||
if (ballVector.z < 0) {
|
||||
shotWasMade = 1;
|
||||
}
|
||||
}
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, shotWasMade);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
44
engines/scumm/he/basketball/shooting.h
Normal file
44
engines/scumm/he/basketball/shooting.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SCUMM_HE_BASKETBALL_SHOOTING_H
|
||||
#define SCUMM_HE_BASKETBALL_SHOOTING_H
|
||||
|
||||
#ifdef ENABLE_HE
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/logic_he.h"
|
||||
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
#define MAX_SHOT_ANGLE 90 // Unless you're doing a behind the back shot, this is the highest angle possible to shoot from
|
||||
#define TEN_FOOT_SHOT_ANGLE 75 // The shot angle used from ten feet out; the shot angle curve is defined by this point
|
||||
#define MIN_SHOT_ANGLE 45 // This is the lowest angle a player will ever shoot from
|
||||
#define SHOT_ANGLE_CUTOFF 3 // This is the horizontal distance / vertical distance ratio where the shot angle is at its lowest; any shot behind this point uses the minimum shot angle
|
||||
#define SHOT_OFFSET_DISTANCE 200 // This is the distance above the basket that the shooter shoots at
|
||||
|
||||
} // End of namespace Scumm
|
||||
|
||||
#endif // ENABLE_HE
|
||||
|
||||
#endif // SCUMM_HE_BASKETBALL_SHOOTING_H
|
||||
112
engines/scumm/he/basketball/trajectory.cpp
Normal file
112
engines/scumm/he/basketball/trajectory.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "scumm/he/intern_he.h"
|
||||
#include "scumm/he/basketball/basketball.h"
|
||||
#include "scumm/he/basketball/collision/bball_collision_support_obj.h"
|
||||
|
||||
namespace Scumm {
|
||||
|
||||
int LogicHEBasketball::u32_userComputeTrajectoryToTarget(const U32FltPoint3D &sourcePoint, const U32FltPoint3D &targetPoint, int speed) {
|
||||
U32FltVector3D trajectory; // The final trajectory of the object
|
||||
float xDist, yDist, zDist; // The distance that the object will move in xyz space
|
||||
float hDist, totalDist;
|
||||
float hAngle, vAngle; // The angle of trajectory from the x axis and from the xy plane
|
||||
float hSpeed; // The speed of the object along the xy plane
|
||||
|
||||
xDist = targetPoint.x - sourcePoint.x;
|
||||
yDist = targetPoint.y - sourcePoint.y;
|
||||
zDist = targetPoint.z - sourcePoint.z;
|
||||
|
||||
hDist = sqrt((xDist * xDist) + (yDist * yDist));
|
||||
totalDist = sqrt((hDist * hDist) + (zDist * zDist));
|
||||
|
||||
if (totalDist < speed)
|
||||
speed = (int)(totalDist + 0.5F);
|
||||
|
||||
hAngle = atan2(yDist, xDist);
|
||||
vAngle = atan2(zDist, totalDist);
|
||||
|
||||
hSpeed = speed * cos(vAngle);
|
||||
|
||||
trajectory.x = hSpeed * cos(hAngle);
|
||||
trajectory.y = hSpeed * sin(hAngle);
|
||||
trajectory.z = speed * sin(vAngle);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(trajectory.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(trajectory.y));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_C, _vm->_basketball->u32FloatToInt(trajectory.z));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userComputeLaunchTrajectory(const U32FltPoint2D &sourcePoint, const U32FltPoint2D &targetPoint, int launchAngle, int iVelocity) {
|
||||
U32FltVector3D trajectory; // The final trajectory of the object
|
||||
float xDist, yDist; // The distance that the object will move in xyz space
|
||||
float vAngle; // The angle of trajectory from the x axis and from the xy plane
|
||||
float hAngle;
|
||||
float hVelocity; // The speed of the object along the xy plane
|
||||
|
||||
xDist = targetPoint.x - sourcePoint.x;
|
||||
yDist = targetPoint.y - sourcePoint.y;
|
||||
|
||||
hAngle = atan2(yDist, xDist);
|
||||
vAngle = (launchAngle * BBALL_M_PI) / 180;
|
||||
|
||||
hVelocity = iVelocity * cos(vAngle);
|
||||
|
||||
trajectory.x = hVelocity * cos(hAngle);
|
||||
trajectory.y = hVelocity * sin(hAngle);
|
||||
trajectory.z = iVelocity * sin(vAngle);
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(trajectory.x));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_B, _vm->_basketball->u32FloatToInt(trajectory.y));
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_C, _vm->_basketball->u32FloatToInt(trajectory.z));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LogicHEBasketball::u32_userComputeAngleBetweenVectors(const U32FltVector3D &vector1, const U32FltVector3D &vector2) {
|
||||
float radiansCosine;
|
||||
float radians;
|
||||
float angle;
|
||||
|
||||
if ((vector1.magnitude() * vector2.magnitude()) == 0) {
|
||||
angle = 0;
|
||||
} else {
|
||||
radiansCosine = (vector1 * vector2) / (vector1.magnitude() * vector2.magnitude());
|
||||
|
||||
if (radiansCosine > 1) {
|
||||
radiansCosine = 1;
|
||||
} else if (radiansCosine < -1) {
|
||||
radiansCosine = -1;
|
||||
}
|
||||
|
||||
radians = acos(radiansCosine);
|
||||
angle = (radians * 180) / BBALL_M_PI;
|
||||
}
|
||||
|
||||
writeScummVar(_vm1->VAR_U32_USER_VAR_A, _vm->_basketball->u32FloatToInt(angle));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // End of namespace Scumm
|
||||
Reference in New Issue
Block a user