diff options
| author | Samuel Rødal <srodal@gmail.com> | 2008-11-28 02:25:30 +0100 |
|---|---|---|
| committer | Samuel Rødal <srodal@gmail.com> | 2008-11-28 02:25:30 +0100 |
| commit | 9ca87699b5a358cfa7304b6a76d02d03d48865ab (patch) | |
| tree | 0d97bda11065ad84275d19fdcf3cd0e642bc4655 | |
| parent | 4f2fd676384dbfd77983c962ad28d2193709bdc2 (diff) | |
Add scripting.
| -rw-r--r-- | main.cpp | 4 | ||||
| -rw-r--r-- | mazescene.cpp | 249 | ||||
| -rw-r--r-- | mazescene.h | 52 | ||||
| -rw-r--r-- | qt3d.pro | 3 |
4 files changed, 271 insertions, 37 deletions
@@ -7,11 +7,11 @@ int main(int argc, char **argv) QPixmapCache::setCacheLimit(100 * 1024); // 100 MB const char *map = - "###&####" + "###&?###" "# #" "& #" "# #" - "# ##?# #" + "# #### #" "& # #" "# @@ &" "# @@ # #" diff --git a/mazescene.cpp b/mazescene.cpp index db6de63..47dee11 100644 --- a/mazescene.cpp +++ b/mazescene.cpp @@ -237,7 +237,9 @@ WallItem::WallItem(MazeScene *scene, const QPointF &a, const QPointF &b, int typ view->setViewport(new QWidget); // no OpenGL here childWidget = view; } else if (type == 5) { - scene->addEntity(new Entity(QPointF(3.5, 2.5))); + Entity *entity = new Entity(QPointF(6.5, 2.5)); + scene->addEntity(entity); + childWidget = new ScriptWidget(scene, entity); } else if (type == 0 || type == 2) { static int index; if (index == 0) { @@ -274,7 +276,7 @@ WallItem::WallItem(MazeScene *scene, const QPointF &a, const QPointF &b, int typ QPointF center = rect.center(); scale = qMin(scale / rect.width(), scale / rect.height()); - m_childItem->translate(0, -0.1); + m_childItem->translate(0, -0.05); m_childItem->scale(scale, scale); m_childItem->translate(-center.x(), -center.y()); } @@ -425,9 +427,9 @@ static inline QRectF rectFromPoint(const QPointF &point, qreal size) return QRectF(point, point).adjusted(-size/2, -size/2, size/2, size/2); } -bool MazeScene::blocked(const QPointF &pos) const +bool MazeScene::blocked(const QPointF &pos, Entity *me) const { - const QRectF rect = rectFromPoint(pos, 0.4); + const QRectF rect = rectFromPoint(pos, me ? 0.7 : 0.25); foreach (WallItem *item, m_walls) { if (item->type() == 6 @@ -445,29 +447,35 @@ bool MazeScene::blocked(const QPointF &pos) const } foreach (Entity *entity, m_entities) { - QRectF entityRect = rectFromPoint(entity->pos(), 0.4); + if (entity == me) + continue; + QRectF entityRect = rectFromPoint(entity->pos(), 0.8); if (entityRect.intersects(rect)) return true; } + if (me) { + QRectF cameraRect = rectFromPoint(m_cameraPos, 0.4); + + if (cameraRect.intersects(rect)) + return true; + } + return false; } -bool MazeScene::tryMove(QPointF &pos, const QPointF &delta) const +bool MazeScene::tryMove(QPointF &pos, const QPointF &delta, Entity *entity) const { - bool moved = false; - if (!blocked(pos + QPointF(delta.x(), 0))) { + const QPointF old = pos; + + if (delta.x() != 0 && !blocked(pos + QPointF(delta.x(), 0), entity)) pos.setX(pos.x() + delta.x()); - moved = true; - } - if (!blocked(pos + QPointF(0, delta.y()))) { + if (delta.y() != 0 && !blocked(pos + QPointF(0, delta.y()), entity)) pos.setY(pos.y() + delta.y()); - moved = true; - } - return moved; + return pos != old; } void MazeScene::updateTransforms() @@ -499,35 +507,43 @@ void MazeScene::updateTransforms() void MazeScene::move() { - qreal oldCameraAngle = m_cameraAngle; - QPointF oldCameraPos = m_cameraPos; - + QSet<Entity *> movedEntities; long elapsed = m_time.elapsed(); + bool walked = false; while (m_simulationTime <= elapsed) { m_cameraAngle += m_turningVelocity; bool walking = false; if (m_walkingVelocity != 0) { - QPointF walkingDir = rotatingTransform(-m_cameraAngle).map(QPointF(0, 1)); - QPointF walkingDelta = m_walkingVelocity * walkingDir; + QPointF walkingDelta = QLineF::fromPolar(m_walkingVelocity, m_cameraAngle - 90).p2(); if (tryMove(m_cameraPos, walkingDelta)) walking = true; } if (m_strafingVelocity != 0) { - QPointF walkingDir = rotatingTransform(-m_cameraAngle).map(QPointF(1, 0)); - QPointF walkingDelta = m_strafingVelocity * walkingDir; + QPointF walkingDelta = QLineF::fromPolar(m_strafingVelocity, m_cameraAngle).p2(); if (tryMove(m_cameraPos, walkingDelta)) walking = true; } + walked = walked || walking; + if (walking) m_walkTime += 5; m_simulationTime += 5; + + foreach (Entity *entity, m_entities) { + if (entity->move(this)) + movedEntities.insert(entity); + } } - if (oldCameraAngle != m_cameraAngle || oldCameraPos != m_cameraPos) + if (walked || m_turningVelocity != 0) { updateTransforms(); + } else { + foreach (Entity *entity, movedEntities) + entity->updateTransform(m_cameraPos, m_cameraAngle, m_walkTime * 0.001); + } } void MazeScene::toggleDoors() @@ -582,14 +598,47 @@ const QImage toAlpha(const QImage &image) Entity::Entity(const QPointF &pos) : ProjectedItem(QRectF(-0.3, -0.4, 0.6, 0.9), false) , m_pos(pos) - , m_angle(0) - , m_walking(true) + , m_angle(180) + , m_walking(false) + , m_walked(false) + , m_turnVelocity(0) + , m_useTurnTarget(false) , m_animationIndex(0) , m_angleIndex(0) { startTimer(300); } +void Entity::walk() +{ + m_walking = true; +} + +void Entity::stop() +{ + m_walking = false; + m_useTurnTarget = false; + m_turnVelocity = 0; +} + +void Entity::turnTowards(qreal x, qreal y) +{ + m_turnTarget = QPointF(x, y); + m_useTurnTarget = true; +} + +void Entity::turnLeft() +{ + m_useTurnTarget = false; + m_turnVelocity = 0.5; +} + +void Entity::turnRight() +{ + m_useTurnTarget = false; + m_turnVelocity = -0.5; +} + static QVector<QImage> loadSoldierImages() { QVector<QImage> images; @@ -600,20 +649,59 @@ static QVector<QImage> loadSoldierImages() return images; } +static inline int mod(int x, int y) +{ + return ((x % y) + y) % y; +} + void Entity::updateTransform(const QPointF &cameraPos, qreal cameraRotation, qreal time) { - QPointF delta = cameraPos - m_pos; - QLineF deltaLine(QPointF(), delta); - qreal angleToCamera = QLineF::fromPolar(1, m_angle) - .angleTo(deltaLine); + qreal angleToCamera = QLineF(m_pos, cameraPos).angle(); + int cameraAngleIndex = mod(qRound(angleToCamera + 22.5), 360) / 45; - m_angleIndex = (int(angleToCamera + 360 + 22.5) / 45) % 8; + m_angleIndex = mod(qRound(cameraAngleIndex * 45 - m_angle + 22.5), 360) / 45; - delta = QLineF::fromPolar(1, 270.1 + 45 * m_angleIndex).p2(); + QPointF delta = QLineF::fromPolar(1, 270.1 + 45 * cameraAngleIndex).p2(); setPosition(m_pos - delta, m_pos + delta); + + updateImage(); ProjectedItem::updateTransform(cameraPos, cameraRotation, time); } +bool Entity::move(MazeScene *scene) +{ + bool moved = false; + if (m_useTurnTarget) { + qreal angleToTarget = QLineF::fromPolar(1, m_angle) + .angleTo(QLineF(m_pos, m_turnTarget)); + + if (angleToTarget != 0) { + if (angleToTarget >= 180) + angleToTarget -= 360; + + if (angleToTarget < 0) + m_angle -= qMin(-angleToTarget, 0.5); + else + m_angle += qMin(angleToTarget, 0.5); + moved = true; + } + } else if (m_turnVelocity != 0) { + m_angle += m_turnVelocity; + moved = true; + } + + m_walked = false; + if (m_walking) { + QPointF walkingDelta = QLineF::fromPolar(0.006, m_angle).p2(); + if (scene->tryMove(m_pos, walkingDelta, this)) { + moved = true; + m_walked = true; + } + } + + return moved; +} + void Entity::timerEvent(QTimerEvent *) { ++m_animationIndex; @@ -623,7 +711,7 @@ void Entity::timerEvent(QTimerEvent *) void Entity::updateImage() { static QVector<QImage> images = loadSoldierImages(); - if (m_walking) + if (m_walked) setImage(images.at(8 + 8 * (m_animationIndex % 4) + m_angleIndex)); else setImage(images.at(m_angleIndex)); @@ -634,3 +722,102 @@ void MazeScene::addEntity(Entity *entity) addItem(entity); m_entities << entity; } + +const char *defaultSource = + "// available functions:\n" + "// entity.turnLeft()\n" + "// entity.turnRight()\n" + "// entity.turnTowards(x, y)\n" + "// entity.walk()\n" + "// entity.stop()\n" + "// rand()\n" + "// script.display()\n" + "\n" + "// available variables:\n" + "// my_x\n" + "// my_y\n" + "// player_x\n" + "// player_y\n" + "// time\n" + "\n" + "entity.stop();\n"; + +static QScriptValue qsRand(QScriptContext *, QScriptEngine *engine) +{ + QScriptValue value(engine, qrand() / (RAND_MAX + 1.0)); + return value; +} + +ScriptWidget::ScriptWidget(MazeScene *scene, Entity *entity) + : m_scene(scene) + , m_entity(entity) +{ + new QVBoxLayout(this); + + m_statusView = new QLineEdit; + m_statusView->setReadOnly(true); + layout()->addWidget(m_statusView); + + m_sourceEdit = new QPlainTextEdit; + m_sourceEdit->setPlainText(QLatin1String(defaultSource)); + layout()->addWidget(m_sourceEdit); + + QPushButton *compileButton = new QPushButton(QLatin1String("Compile")); + layout()->addWidget(compileButton); + + connect(compileButton, SIGNAL(clicked()), this, SLOT(updateSource())); + + m_engine = new QScriptEngine(this); + QScriptValue entityObject = m_engine->newQObject(m_entity); + m_engine->globalObject().setProperty("entity", entityObject); + QScriptValue widgetObject = m_engine->newQObject(this); + m_engine->globalObject().setProperty("script", widgetObject); + m_engine->globalObject().setProperty("rand", m_engine->newFunction(qsRand)); + + m_engine->setProcessEventsInterval(5); + + resize(300, 400); + updateSource(); + + startTimer(50); + m_time.start(); +} + +void ScriptWidget::timerEvent(QTimerEvent *event) +{ + m_engine->abortEvaluation(); + QPointF player = m_scene->cameraPosition(); + QPointF entity = m_entity->pos(); + + QScriptValue px(m_engine, player.x()); + QScriptValue py(m_engine, player.y()); + QScriptValue ex(m_engine, entity.x()); + QScriptValue ey(m_engine, entity.y()); + QScriptValue time(m_engine, m_time.elapsed()); + + m_engine->globalObject().setProperty("player_x", px); + m_engine->globalObject().setProperty("player_y", py); + m_engine->globalObject().setProperty("my_x", ex); + m_engine->globalObject().setProperty("my_y", ey); + m_engine->globalObject().setProperty("time", time); + + m_engine->evaluate(m_source); + if (m_engine->hasUncaughtException()) { + QString text = m_engine->uncaughtException().toString(); + m_statusView->setText(text); + } +} + +void ScriptWidget::display(QScriptValue value)//const QString &string) +{ + m_statusView->setText(value.toString()); +} + +void ScriptWidget::updateSource() +{ + m_source = m_sourceEdit->toPlainText(); + if (m_engine->canEvaluate(m_source)) + m_statusView->setText(QLatin1String("Evaluation succeeded")); + else + m_statusView->setText(QLatin1String("Evaluation failed")); +} diff --git a/mazescene.h b/mazescene.h index 0440fd7..b89d2f8 100644 --- a/mazescene.h +++ b/mazescene.h @@ -1,11 +1,15 @@ #include <QGraphicsItem> #include <QGraphicsScene> #include <QGraphicsView> +#include <QLineEdit> +#include <QPlainTextEdit> #include <QPointF> #include <QPushButton> #include <QTime> #include <QTimeLine> +#include <QScriptEngine> + class MazeScene; class View : public QGraphicsView @@ -61,12 +65,22 @@ private: class Entity : public QObject, public ProjectedItem { + Q_OBJECT public: Entity(const QPointF &pos); void updateTransform(const QPointF &cameraPos, qreal cameraRotation, qreal time); QPointF pos() const { return m_pos; } + bool move(MazeScene *scene); + +public slots: + void turnTowards(qreal x, qreal y); + void turnLeft(); + void turnRight(); + void walk(); + void stop(); + protected: void timerEvent(QTimerEvent *event); @@ -77,6 +91,12 @@ private: QPointF m_pos; qreal m_angle; bool m_walking; + bool m_walked; + + qreal m_turnVelocity; + QPointF m_turnTarget; + + bool m_useTurnTarget; int m_animationIndex; int m_angleIndex; @@ -92,6 +112,10 @@ public: void addWall(const QPointF &a, const QPointF &b, int type); void drawBackground(QPainter *painter, const QRectF &rect); + bool tryMove(QPointF &pos, const QPointF &delta, Entity *entity = 0) const; + + QPointF cameraPosition() { return m_cameraPos; } + protected: void keyPressEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event); @@ -107,8 +131,7 @@ private slots: void moveDoors(qreal value); private: - bool blocked(const QPointF &pos) const; - bool tryMove(QPointF &pos, const QPointF &delta) const; + bool blocked(const QPointF &pos, Entity *entity) const; void updateTransforms(); QVector<WallItem *> m_walls; @@ -130,3 +153,28 @@ private: int m_width; int m_height; }; + +class ScriptWidget : public QWidget +{ + Q_OBJECT +public: + ScriptWidget(MazeScene *scene, Entity *entity); + +public slots: + void display(QScriptValue value); + +private slots: + void updateSource(); + +protected: + void timerEvent(QTimerEvent *event); + +private: + MazeScene *m_scene; + Entity *m_entity; + QScriptEngine *m_engine; + QPlainTextEdit *m_sourceEdit; + QLineEdit *m_statusView; + QString m_source; + QTime m_time; +}; @@ -7,8 +7,7 @@ TARGET = DEPENDPATH += . INCLUDEPATH += . -QT += webkit -QT += opengl +QT += webkit opengl script # Input HEADERS += mazescene.h |
