123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497 |
- #include "Welt2D.h"
- #include "Bild.h"
- using namespace Framework;
- Object2D::Object2D()
- : ReferenceCounter()
- {
- rSpeed = 0;
- rotation = 0;
- size = 1;
- collision = 1;
- }
- Object2D::~Object2D() {}
- // Übergibt einen Void Funktionspointer auf eine Aktion die einmalig vom
- // Hauptthread ausgeführt werden soll. (Passiert nach dem Tick)
- void Object2D::postAction(std::function<void()> action)
- {
- actions.push(action);
- }
- void Object2D::explosion(Vertex worldPos, float intensity)
- {
- intensity /= (position - worldPos).getLengthSq();
- speed += (position - worldPos) * intensity;
- }
- void Object2D::impuls(Vertex start, Vertex speed, float strength) {}
- void Object2D::setSpeed(Vertex speed)
- {
- this->speed = speed;
- }
- void Object2D::setSpeed(float x, float y)
- {
- speed.x = x, speed.y = y;
- }
- void Object2D::setPosition(Vertex pos)
- {
- position = pos;
- }
- void Object2D::setPosition(float x, float y)
- {
- position = Vertex(x, y);
- }
- void Object2D::setDrehungSpeed(float ds)
- {
- rSpeed = ds;
- }
- void Object2D::setDrehung(float drehung)
- {
- rotation = drehung;
- while (rotation > PI * 2)
- rotation -= (float)PI * 2;
- while (rotation < 0)
- rotation += (float)PI * 2;
- }
- void Object2D::addDrehung(float drehung)
- {
- rotation += drehung;
- while (rotation > PI * 2)
- rotation -= (float)PI * 2;
- while (rotation < 0)
- rotation += (float)PI * 2;
- }
- void Object2D::setSize(float size)
- {
- this->size = size;
- }
- void Object2D::addSize(float size)
- {
- this->size += size;
- }
- void Object2D::setCollision(bool handle)
- {
- collision = handle;
- }
- bool Object2D::handleCollision(Object2D* obj)
- {
- Vertex hp;
- if (istModelInnen(obj, &hp)) // hp wird auf den aufprallpunkt gesetzt
- {
- // Geschwindigkeit von diesem objekt mit rotation
- Vertex v1
- = getSpeed()
- + getWorldDir(getObjectPos(hp).rotation(rSpeed) - getObjectPos(hp));
- // Geschwindigkeit des anderen Objektes mit rotation
- Vertex v2
- = obj->getSpeed()
- + getWorldDir(obj->getObjectPos(hp).rotation(obj->getDrehungSpeed())
- - obj->getObjectPos(hp));
- if ((hp - obj->getPosition()).getLengthSq()
- > (hp + v1 * 0.03f - obj->getPosition()).getLengthSq()
- || (hp - getPosition()).getLengthSq()
- > (hp + v2 * 0.03f - getPosition()).getLengthSq())
- { // nur wenn sie sich aufeinander zu bewegen
- float m1 = getMasse() * v1.getLength(); // fläche von Objekt 1
- float m2 = obj->getMasse() * v2.getLength(); // fläche von Objekt 2
- if (m1 == 0 || m2 == 0)
- return 0; // falls ein objekt keine masse hat ignoriere die
- // kollision
- float nm1 = m1 / (m1 + m2); // koeffizient für objekt 2
- float nm2 = m2 / (m1 + m2); // koeffizient für Objekt 1
- // rSpeed *= nm1; // Drehgeschwindigkeit anpassen (objekt 1)
- // speed *= nm1; // Bewegungsgeschwindigkeit anpassen (objekt 1)
- // obj->setDrehungSpeed( obj->getDrehungSpeed() * nm2 ); //
- // Drehgeschwindigkeit anpassen (objekt 2) obj->setSpeed(
- // obj->getSpeed() * nm2 ); // Bewegungsgeschwindigkeit anpassen
- // (objekt 2)
- float speedSumLength
- = getSpeed().getLength() + obj->getSpeed().getLength();
- rSpeed = 0;
- speed = Vertex();
- obj->setDrehungSpeed(0);
- obj->setSpeed(Vertex());
- if (v2.x || v2.y) impuls(hp - v2, v2);
- if (getSpeed().getLength() > 0)
- setSpeed(getSpeed().normalize() * speedSumLength * nm2);
- if (v1.x || v1.y) obj->impuls(hp - v1, v1);
- if (obj->getSpeed().getLength() > 0)
- obj->setSpeed(
- obj->getSpeed().normalize() * speedSumLength * nm1);
- return 1;
- }
- }
- return 0;
- }
- bool Object2D::tick(const WeltInfo& info, double zeit)
- {
- while (!actions.empty())
- {
- actions.front()();
- actions.pop();
- }
- rotation += rSpeed * (float)zeit;
- while (rotation > PI * 2)
- rotation -= (float)PI * 2;
- while (rotation < 0)
- rotation += (float)PI * 2;
- position += speed * (float)zeit;
- while (zeit > 1)
- {
- rSpeed -= rSpeed
- - (rSpeed / (1 + info.airResistance * getLuftWiederstand()));
- speed -= speed
- - (speed / (1 + info.airResistance * getLuftWiederstand()));
- zeit -= 1;
- }
- rSpeed
- -= (rSpeed - (rSpeed / (1 + info.airResistance * getLuftWiederstand())))
- * (float)zeit;
- speed -= (speed - (speed / (1 + info.airResistance * getLuftWiederstand())))
- * (float)zeit;
- if (info.circular && info.hasSize && info.size.x && info.size.y)
- {
- while (position.x > (float)info.size.x)
- position.x -= (float)info.size.x;
- while (position.x < 0)
- position.x += (float)info.size.x;
- while (position.y > (float)info.size.y)
- position.y -= (float)info.size.y;
- while (position.y < 0)
- position.y += (float)info.size.y;
- }
- return rSpeed != 0 || speed != Vertex(0, 0);
- }
- bool Object2D::istPunktInnen(Vertex p, bool ignoreTransparent) const
- {
- return 0;
- }
- bool Object2D::istLinieInnen(Vertex a, Vertex b, bool ignoreTransparent) const
- {
- return 0;
- }
- bool Object2D::istModelInnen(
- const Object2D* zObj, Vertex* sp, bool end, bool ignoreTransparent) const
- {
- return 0;
- }
- Mat3<float> Object2D::getObjectMatrix() const
- {
- return Mat3<float>::translation(position) * Mat3<float>::rotation(rotation)
- * Mat3<float>::scaling(size);
- }
- Mat3<float> Object2D::getInverseObjectMatrix() const
- {
- return Mat3<float>::scaling(1 / size) * Mat3<float>::rotation(-rotation)
- * Mat3<float>::translation(-position);
- }
- Vertex Object2D::getObjectPos(Vertex worldPos) const
- {
- return (worldPos - position).rotation(-rotation) * (1 / size);
- }
- Vertex Object2D::getObjectDir(Vertex worldDir) const
- {
- return Vertex(worldDir.x, worldDir.y).rotation(-rotation) * (1 / size);
- }
- Vertex Object2D::getWorldPos(Vertex objectPos) const
- {
- return (Vertex(objectPos) * size).rotation(rotation) + position;
- }
- Vertex Object2D::getWorldDir(Vertex objectDir) const
- {
- return (Vertex(objectDir) * size).rotation(rotation);
- }
- Vertex Object2D::getSpeed() const
- {
- return speed;
- }
- Vertex Object2D::getPosition() const
- {
- return position;
- }
- float Object2D::getDrehungSpeed() const
- {
- return rSpeed;
- }
- float Object2D::getDrehung() const
- {
- return rotation;
- }
- float Object2D::getSize() const
- {
- return size;
- }
- bool Object2D::calcHitPoint(Vertex pos, Vertex dir, Vertex& hitpoint) const
- {
- return 0;
- }
- float Object2D::getLuftWiederstand() const
- {
- return 0;
- }
- float Object2D::getMasse() const
- {
- return 0;
- }
- bool Object2D::canCollide()
- {
- return collision;
- }
- Welt2D::Welt2D()
- : ReferenceCounter()
- {
- objects = new RCArray<Object2D>();
- memset(&info, 0, sizeof(WeltInfo));
- }
- Welt2D::~Welt2D()
- {
- objects->release();
- }
- void Welt2D::setAirResistance(float resistance)
- {
- info.airResistance = resistance;
- }
- void Welt2D::setSize(int width, int height)
- {
- info.size.x = width;
- info.size.y = height;
- }
- void Welt2D::setSize(bool hasSize)
- {
- info.hasSize = hasSize;
- }
- void Welt2D::setCircular(bool circular)
- {
- info.circular = circular;
- }
- Object2D* Welt2D::zObjectAt(int x, int y, bool ignoreTransparentFlag)
- {
- for (auto o : *objects)
- {
- if (o->istPunktInnen(Punkt(x, y), ignoreTransparentFlag)) return o;
- }
- return 0;
- }
- Object2D* Welt2D::getObjectAt(int x, int y, bool ignoreTransparentFlag)
- {
- Object2D* tmp = zObjectAt(x, y, ignoreTransparentFlag);
- return tmp ? dynamic_cast<Object2D*>(tmp->getThis()) : 0;
- }
- void Welt2D::addObject(Object2D* obj)
- {
- objects->add(obj);
- }
- void Welt2D::removeObject(Object2D* zObj)
- {
- int anz = objects->getEintragAnzahl();
- for (int i = 0; i < anz; i++)
- {
- if (objects->z(i) == zObj)
- {
- objects->remove(i);
- i--;
- }
- }
- }
- void Welt2D::removeAll()
- {
- objects->leeren();
- }
- void Welt2D::explosion(Vertex worldPos, float intensity, float maxRad)
- {
- maxRad = maxRad * maxRad;
- for (auto obj : *objects)
- {
- if (info.circular && info.hasSize && info.size.x && info.size.y)
- {
- Vertex offsets[] = {Vertex(0, 0),
- Vertex((float)info.size.x, 0),
- Vertex(0, (float)info.size.y),
- Vertex((float)info.size.x, (float)info.size.y),
- Vertex((float)-info.size.x, 0),
- Vertex(0, (float)-info.size.y),
- Vertex((float)-info.size.x, (float)-info.size.y),
- Vertex((float)-info.size.x, (float)info.size.y),
- Vertex((float)info.size.x, (float)-info.size.y)};
- Vertex offset;
- float minDist = INFINITY;
- for (Vertex p : offsets)
- {
- float dist
- = (obj->getPosition() - (worldPos - p)).getLengthSq();
- if (dist < minDist)
- {
- minDist = dist;
- offset = p;
- }
- }
- if ((obj->getPosition() - (worldPos - offset)).getLengthSq()
- < maxRad)
- obj->explosion(worldPos - offset, intensity);
- }
- else if ((obj->getPosition() - worldPos).getLengthSq() < maxRad)
- obj->explosion(worldPos, intensity);
- }
- }
- void Welt2D::impuls(Vertex worldPos, Vertex worldDir)
- {
- Vertex hitPoint;
- float dist = INFINITY;
- Object2D* o = 0;
- for (auto obj : *objects)
- {
- if (obj->calcHitPoint(worldPos, worldDir, hitPoint))
- {
- if ((hitPoint - worldPos).getLengthSq() < dist)
- {
- dist = (hitPoint - worldPos).getLengthSq();
- o = obj;
- }
- }
- }
- if (o) o->impuls(worldPos, worldDir);
- }
- bool Welt2D::tick(double zeit)
- {
- bool ret = 0;
- for (auto obj = objects->begin(); obj; obj++)
- {
- if (obj.hasNext() && obj->canCollide())
- {
- for (auto obj2 = obj.next(); obj2; obj2++)
- {
- if (obj2->canCollide()) obj->handleCollision(obj2);
- }
- }
- ret |= obj->tick(info, zeit);
- }
- return ret;
- }
- void Welt2D::render(Mat3<float>& kamMat,
- Punkt size,
- Bild& zRObj,
- int xOffset,
- int yOffset,
- const char* kamName)
- {
- for (auto obj : *objects)
- {
- Rect2<float> bnd = obj->getBoundingBox();
- Vertex topRight = Vertex(bnd.bottomRight.x, bnd.topLeft.y);
- Vertex bottomLeft = Vertex(bnd.topLeft.x, bnd.bottomRight.y);
- Mat3<float> km
- = kamMat
- * Mat3<float>::translation(Vertex((float)xOffset, (float)yOffset));
- bnd.bottomRight = km * bnd.bottomRight;
- bnd.topLeft = km * bnd.topLeft;
- topRight = km * topRight;
- bottomLeft = km * bottomLeft;
- if ((bnd.bottomRight.x >= 0 && bnd.bottomRight.x < (float)size.x)
- || (bnd.bottomRight.y >= 0 && bnd.bottomRight.y < (float)size.y)
- || (bnd.topLeft.x >= 0 && bnd.topLeft.x < (float)size.x)
- || (bnd.topLeft.y >= 0 && bnd.topLeft.y < (float)size.y)
- || (topRight.x >= 0 && topRight.x < (float)size.x)
- || (topRight.y >= 0 && topRight.y < (float)size.y)
- || (bottomLeft.x >= 0 && bottomLeft.x < (float)size.x)
- || (bottomLeft.y >= 0 && bottomLeft.y < (float)size.y))
- obj->render(km, zRObj, kamName);
- }
- }
- void Welt2D::render(
- Mat3<float>& kamMat, Punkt size, Bild& zRObj, const char* kamName)
- {
- if (!info.hasSize || !info.circular)
- {
- for (auto obj : *objects)
- {
- Rect2<float> bnd = obj->getBoundingBox();
- Vertex topRight = Vertex(bnd.topLeft.y, bnd.bottomRight.x);
- Vertex bottomLeft = Vertex(bnd.topLeft.x, bnd.bottomRight.y);
- bnd.bottomRight = kamMat * bnd.bottomRight;
- bnd.topLeft = kamMat * bnd.topLeft;
- topRight = kamMat * topRight;
- bottomLeft = kamMat * bottomLeft;
- if ((bnd.bottomRight.x >= 0 && bnd.bottomRight.x < (float)size.x)
- || (bnd.bottomRight.y >= 0 && bnd.bottomRight.y < (float)size.y)
- || (bnd.topLeft.x >= 0 && bnd.topLeft.x < (float)size.x)
- || (bnd.topLeft.y >= 0 && bnd.topLeft.y < (float)size.y)
- || (topRight.x >= 0 && topRight.x < (float)size.x)
- || (topRight.y >= 0 && topRight.y < (float)size.y)
- || (bottomLeft.x >= 0 && bottomLeft.x < (float)size.x)
- || (bottomLeft.y >= 0 && bottomLeft.y < (float)size.y))
- obj->render(kamMat, zRObj, kamName);
- }
- }
- else if (info.circular)
- {
- render(kamMat, size, zRObj, 0, 0, kamName);
- render(kamMat, size, zRObj, info.size.x, 0, kamName);
- render(kamMat, size, zRObj, 0, info.size.y, kamName);
- render(kamMat, size, zRObj, info.size.x, info.size.y, kamName);
- render(kamMat, size, zRObj, -info.size.x, 0, kamName);
- render(kamMat, size, zRObj, 0, -info.size.y, kamName);
- render(kamMat, size, zRObj, -info.size.x, -info.size.y, kamName);
- render(kamMat, size, zRObj, -info.size.x, +info.size.y, kamName);
- render(kamMat, size, zRObj, +info.size.x, -info.size.y, kamName);
- }
- }
- const WeltInfo& Welt2D::getWorldInfo() const
- {
- return info;
- }
- Iterator<Object2D*> Welt2D::getMembers()
- {
- return objects->begin();
- }
|