# HG changeset patch # User zzzzrrr # Date 1237994905 14400 # Node ID 7f74e064dad5da1011d45ffdb7ffd5944f8b3a12 # Parent 82efafc87d5445dccedb2ee653d0445313ed26e3 refactored code diff -r 82efafc87d54 -r 7f74e064dad5 ai.d --- a/ai.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2009, Mason Green (zzzzrrr) - * http://www.dsource.org/projects/openmelee - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the polygonal nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -module openmelee.ai; - -import tango.io.Stdout : Stdout; -import tango.math.Math : atan2, abs, PI; - -import blaze.common.bzMath: bzVec2, bzClamp; -import openmelee.steer : Steer; -import openmelee.ship : Ship; - -class AI { - - - Steer steer; - Ship ship; - float maxPredictionTime = 0.1f; - - this(Ship ship) { - this.ship = ship; - steer = new Steer(ship); - } - - void move(Ship enemy) { - - // Elementary steering AI - - steer.update(); - bzVec2 st; - st = steer.steerForPursuit(enemy.state, maxPredictionTime); - ship.state.target = st; - st = ship.rBody.localPoint(st); - float x = st.x; - float y = st.y; - st = -bzVec2(y,-x); - float angle = atan2(st.x, st.y); - - if(abs(angle) > 0.05) { - if(!ship.state.turn) { - if(st.x >= 0) { - ship.turnRight(); - ship.state.turn = true; - } else { - ship.state.turn = true; - ship.turnLeft(); - } - } - } else { - ship.rBody.angularVelocity = 0.0f; - ship.state.turn = false; - } - - float range = (ship.state.position - enemy.state.position).length; - if(range > 2 && abs(angle) < PI/4) { - ship.thrust(); - } - } - -} diff -r 82efafc87d54 -r 7f74e064dad5 ai/ai.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ai/ai.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * http://www.dsource.org/projects/openmelee + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.ai.ai; + +import tango.io.Stdout : Stdout; +import tango.math.Math : atan2, abs, PI; + +import blaze.common.bzMath: bzVec2, bzClamp; + +import openmelee.ai.steer : Steer; +import openmelee.ships.ship : Ship; + +class AI { + + + Steer steer; + Ship ship; + float maxPredictionTime = 0.1f; + + this(Ship ship) { + this.ship = ship; + steer = new Steer(ship); + } + + void move(Ship enemy) { + + // Elementary steering AI + + steer.update(); + bzVec2 st; + st = steer.steerForPursuit(enemy.state, maxPredictionTime); + ship.state.target = st; + st = ship.rBody.localPoint(st); + float x = st.x; + float y = st.y; + st = -bzVec2(y,-x); + float angle = atan2(st.x, st.y); + + if(abs(angle) > 0.05) { + if(!ship.state.turn) { + if(st.x >= 0) { + ship.turnRight(); + ship.state.turn = true; + } else { + ship.state.turn = true; + ship.turnLeft(); + } + } + } else { + ship.rBody.angularVelocity = 0.0f; + ship.state.turn = false; + } + + float range = (ship.state.position - enemy.state.position).length; + if(range > 2 && abs(angle) < PI/4) { + ship.thrust(); + } + } + +} diff -r 82efafc87d54 -r 7f74e064dad5 ai/human.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ai/human.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * http://www.dsource.org/projects/openmelee + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.ai.human; + +import xf.hybrid.Event; +import xf.input.KeySym; + +import openmelee.ships.ship; + +class Human +{ + + Ship ship; + + this(Ship ship) { + this.ship = ship; + } + + EventHandling onClick(MouseButtonEvent e) { + return EventHandling.Stop; + } + + EventHandling onKey(KeyboardEvent e) { + // Key pressed + if (e.down) { + switch (e.keySym) { + case KeySym.space: + drawAABBs = !drawAABBs; + break; + case KeySym.Escape: + quit = true; + break; + case KeySym.Up: + thrust = true; + break; + case KeySym.Left: + ship.turnLeft(); + break; + case KeySym.Right: + ship.turnRight(); + break; + case KeySym.Down: + break; + default: + break; + } + // Key released + } else { + if(e.keySym == KeySym.Up) { + thrust = false; + } else if (e.keySym == KeySym.Left || e.keySym == KeySym.Right) { + ship.rBody.angularVelocity = 0.0f; + } + } + return EventHandling.Stop; + } + + // Mouse move + EventHandling onMove(MouseMoveEvent e) { + return EventHandling.Stop; + } + + EventHandling onDT(TimeUpdateEvent e){ + return EventHandling.Continue; + } + + EventHandling onMouseEnter(MouseEnterEvent e) { + return EventHandling.Continue; + } + + EventHandling onMouseLeave(MouseLeaveEvent e) { + return EventHandling.Continue; + } + + bool quit; + bool thrust; + bool drawAABBs; +} diff -r 82efafc87d54 -r 7f74e064dad5 ai/steer.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ai/steer.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * http://www.dsource.org/projects/openmelee + * Based on OpenSteer, Copyright (c) 2002-2003, Sony Computer Entertainment America + * Original author: Craig Reynolds + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.ai.steer; + +import blaze.common.bzMath: bzDot, bzClamp, bzVec2; +import blaze.dynamics.bzBody: bzBody; + +import openmelee.ships.ship : Ship, State; +import openmelee.ai.utilities; + +class Steer +{ + // Constructor: initializes state + this (Ship ship) + { + m_ship = ship; + } + + struct PathIntersection + { + bool intersect; + float distance; + bzVec2 surfacePoint; + bzVec2 surfaceNormal; + bzBody obstacle; + } + + // reset state + void reset () { + // initial state of wander behavior + m_wanderSide = 0; + m_wanderUp = 0; + } + + void update() { + m_position = m_ship.state.position; + m_velocity = m_ship.state.velocity; + m_speed = m_ship.state.speed; + m_maxForce = m_ship.state.maxForce; + m_forward = m_ship.state.forward; + } + + // -------------------------------------------------- steering behaviors + + bzVec2 steerForWander (float dt) { + // random walk m_wanderSide and m_wanderUp between -1 and +1 + float speed = 12 * dt; // maybe this (12) should be an argument? + m_wanderSide = scalarRandomWalk (m_wanderSide, speed, -1, +1); + m_wanderUp = scalarRandomWalk (m_wanderUp, speed, -1, +1); + + // return a pure lateral steering vector: (+/-Side) + (+/-Up) + return (m_side * m_wanderSide) + (m_up * m_wanderUp); + } + + // Seek behavior + bzVec2 steerForSeek (bzVec2 target) { + bzVec2 desiredVelocity = target - m_position; + return desiredVelocity - m_velocity; + } + + // Flee behavior + bzVec2 steerForFlee (bzVec2 target) { + bzVec2 desiredVelocity = m_position - target; + return desiredVelocity - m_velocity; + } + + /* + // xxx proposed, experimental new seek/flee [cwr 9-16-02] + bzVec2 xxxsteerForFlee (bzVec2 target) { + bzVec2 offset = m_position - target; + bzVec2 desiredVelocity = bzClamp(offset.truncateLength (maxSpeed ()); + return desiredVelocity - m_velocity; + } + + bzVec2 xxxsteerForSeek (bzVec2 target) { + // bzVec2 offset = target - position; + bzVec2 offset = target - m_position; + bzVec2 desiredVelocity = offset.truncateLength (maxSpeed ()); //xxxnew + return desiredVelocity - m_velocity; + } + */ + + /* + // ------------------------------------------------------------------------ + // Obstacle Avoidance behavior + // + // Returns a steering force to avoid a given obstacle. The purely + // lateral steering force will turn our vehicle towards a silhouette edge + // of the obstacle. Avoidance is required when (1) the obstacle + // intersects the vehicle's current path, (2) it is in front of the + // vehicle, and (3) is within minTimeToCollision seconds of travel at the + // vehicle's current velocity. Returns a zero vector value (bzVec2::zero) + // when no avoidance is required. + bzVec2 steerToAvoidObstacle (float minTimeToCollision, Obstacle obstacle) { + + bzVec2 avoidance = obstacle.steerToAvoid (this, minTimeToCollision); + return avoidance; + } + + // avoids all obstacles in an ObstacleGroup + */ + + bzVec2 steerToAvoidObstacles (float minTimeToCollision, bzBody obstacles) { + + bzVec2 avoidance; + PathIntersection nearest, next; + float minDistanceToCollision = minTimeToCollision * m_speed; + + next.intersect = false; + nearest.intersect = false; + + // test all obstacles for intersection with my forward axis, + // select the one whose point of intersection is nearest + for (bzBody o; o; o = o.next) { + // This code which presumes the obstacle is spherical + //findNextIntersectionWithSphere (o, next); + + if (!nearest.intersect || (next.intersect && next.distance < nearest.distance)) { + nearest = next; + } + } + + // when a nearest intersection was found + if (nearest.intersect && (nearest.distance < minDistanceToCollision)) { + // compute avoidance steering force: take offset from obstacle to me, + // take the component of that which is lateral (perpendicular to my + // forward direction), set length to maxForce, add a bit of forward + // component (in capture the flag, we never want to slow down) + bzVec2 offset = m_position - nearest.obstacle.position; + //avoidance = Vector3Helpers.PerpendicularComponent(offset, this.Forward); + avoidance.normalize; + avoidance *= m_maxForce; + avoidance += m_forward * m_maxForce * 0.75f; + } + + return avoidance; + } + + /* + // ------------------------------------------------------------------------ + // Unaligned collision avoidance behavior: avoid colliding with other + // nearby vehicles moving in unconstrained directions. Determine which + // (if any) other other vehicle we would collide with first, then steers + // to avoid the site of that potential collision. Returns a steering + // force vector, which is zero length if there is no impending collision. + + bzVec2 steerToAvoidNeighbors (float minTimeToCollision, AVGroup others) { + + // first priority is to prevent immediate interpenetration + bzVec2 separation = steerToAvoidCloseNeighbors (0, others); + if (separation != bzVec2::zero) return separation; + + // otherwise, go on to consider potential future collisions + float steer = 0; + Ship threat; + + // Time (in seconds) until the most immediate collision threat found + // so far. Initial value is a threshold: don't look more than this + // many frames into the future. + float minTime = minTimeToCollision; + + // xxx solely for annotation + bzVec2 xxxThreatPositionAtNearestApproach; + bzVec2 xxxOurPositionAtNearestApproach; + + // for each of the other vehicles, determine which (if any) + // pose the most immediate threat of collision. + for (AVIterator i = others.begin(); i != others.end(); i++) + { + Ship other = i; + if (other !is this) + { + // avoid when future positions are this close (or less) + float collisionDangerThreshold = radius * 2; + + // predicted time until nearest approach of "this" and "other" + float time = predictNearestApproachTime (other); + + // If the time is in the future, sooner than any other + // threatened collision... + if ((time >= 0) (time < minTime)) + { + // if the two will be close enough to collide, + // make a note of it + if (computeNearestApproachPositions (other, time) + < collisionDangerThreshold) + { + minTime = time; + threat = other; + xxxThreatPositionAtNearestApproach + = hisPositionAtNearestApproach; + xxxOurPositionAtNearestApproach + = ourPositionAtNearestApproach; + } + } + } + } + + // if a potential collision was found, compute steering to avoid + if (threat) + { + // parallel: +1, perpendicular: 0, anti-parallel: -1 + float parallelness = m_forward.dot(threat.forward); + float angle = 0.707f; + + if (parallelness < -angle) + { + // anti-parallel "head on" paths: + // steer away from future threat position + bzVec2 offset = xxxThreatPositionAtNearestApproach - m_position; + float sideDot = offset.dot(m_side()); + steer = (sideDot > 0) ? -1.0f : 1.0f; + } + else + { + if (parallelness > angle) + { + // parallel paths: steer away from threat + bzVec2 offset = threat.position - m_position; + float sideDot = bzDot(offset, m_side); + steer = (sideDot > 0) ? -1.0f : 1.0f; + } + else + { + // perpendicular paths: steer behind threat + // (only the slower of the two does this) + if (threat.speed() <= speed) + { + float sideDot = bzDot(m_side, threat.velocity); + steer = (sideDot > 0) ? -1.0f : 1.0f; + } + } + } + } + + return m_side() * steer; + } + */ + + // Given two vehicles, based on their current positions and velocities, + // determine the time until nearest approach + float predictNearestApproachTime (State other) { + + // imagine we are at the origin with no velocity, + // compute the relative velocity of the other vehicle + bzVec2 myVelocity = m_velocity; + bzVec2 otherVelocity = other.velocity; + bzVec2 relVelocity = otherVelocity - myVelocity; + float relSpeed = relVelocity.length; + + // for parallel paths, the vehicles will always be at the same distance, + // so return 0 (aka "now") since "there is no time like the present" + if (relSpeed == 0) return 0; + + // Now consider the path of the other vehicle in this relative + // space, a line defined by the relative position and velocity. + // The distance from the origin (our vehicle) to that line is + // the nearest approach. + + // Take the unit tangent along the other vehicle's path + bzVec2 relTangent = relVelocity / relSpeed; + + // find distance from its path to origin (compute offset from + // other to us, find length of projection onto path) + bzVec2 relPosition = m_position - other.position; + float projection = bzDot(relTangent, relPosition); + + return projection / relSpeed; + } + + // Given the time until nearest approach (predictNearestApproachTime) + // determine position of each vehicle at that time, and the distance + // between them + float computeNearestApproachPositions (State other, float time) { + + bzVec2 myTravel = m_forward * m_speed * time; + bzVec2 otherTravel = other.forward * other.speed * time; + + bzVec2 myFinal = m_position + myTravel; + bzVec2 otherFinal = other.position + otherTravel; + + return (myFinal - otherFinal).length; + } + + // ------------------------------------------------------------------------ + // pursuit of another vehicle ( version with ceiling on prediction time) + + bzVec2 steerForPursuit (State quarry) { + return steerForPursuit (quarry, float.max); + } + + bzVec2 steerForPursuit (State quarry, float maxPredictionTime) { + + // offset from this to quarry, that distance, unit vector toward quarry + bzVec2 offset = quarry.position - m_position; + float distance = offset.length; + bzVec2 unitOffset = offset / distance; + + // how parallel are the paths of "this" and the quarry + // (1 means parallel, 0 is pependicular, -1 is anti-parallel) + float parallelness = bzDot(m_forward , quarry.forward); + + // how "forward" is the direction to the quarry + // (1 means dead ahead, 0 is directly to the side, -1 is straight back) + float forwardness = bzDot(m_forward , unitOffset); + + float directTravelTime = distance / m_speed; + int f = intervalComparison (forwardness, -0.707f, 0.707f); + int p = intervalComparison (parallelness, -0.707f, 0.707f); + + float timeFactor = 0; // to be filled in below + + // Break the pursuit into nine cases, the cross product of the + // quarry being [ahead, aside, or behind] us and heading + // [parallel, perpendicular, or anti-parallel] to us. + switch (f) + { + case +1: + switch (p) + { + case +1: // ahead, parallel + timeFactor = 4; + break; + case 0: // ahead, perpendicular + timeFactor = 1.8f; + break; + case -1: // ahead, anti-parallel + timeFactor = 0.85f; + break; + } + break; + case 0: + switch (p) + { + case +1: // aside, parallel + timeFactor = 1; + break; + case 0: // aside, perpendicular + timeFactor = 0.8f; + break; + case -1: // aside, anti-parallel + timeFactor = 4; + break; + } + break; + case -1: + switch (p) + { + case +1: // behind, parallel + timeFactor = 0.5f; + break; + case 0: // behind, perpendicular + timeFactor = 2; + break; + case -1: // behind, anti-parallel + timeFactor = 2; + break; + } + break; + } + + // estimated time until intercept of quarry + float et = directTravelTime * timeFactor; + + // xxx experiment, if kept, this limit should be an argument + float etl = (et > maxPredictionTime) ? maxPredictionTime : et; + + // estimated position of quarry at intercept + bzVec2 target = quarry.predictFuturePosition(etl); + + return target; //steerForSeek (target); + } + + // ------------------------------------------------------------------------ + // evasion of another vehicle + bzVec2 steerForEvasion (State menace, float maxPredictionTime) { + + // offset from this to menace, that distance, unit vector toward menace + bzVec2 offset = menace.position - m_position; + float distance = offset.length; + + float roughTime = distance / menace.speed; + float predictionTime = ((roughTime > maxPredictionTime) ? maxPredictionTime : roughTime); + bzVec2 target = menace.predictFuturePosition (predictionTime); + + return steerForFlee (target); + } + + + // ------------------------------------------------------------------------ + // tries to maintain a given speed, returns a maxForce-clipped steering + // force along the forward/backward axis + bzVec2 steerForTargetSpeed (float targetSpeed) { + float mf = m_maxForce; + float speedError = targetSpeed - m_speed; + return m_forward * bzClamp(speedError, -mf, +mf); + } + + + // ----------------------------------------------------------- utilities + bool isAhead (bzVec2 target) {return isAhead (target, 0.707f);}; + bool isAside (bzVec2 target) {return isAside (target, 0.707f);}; + bool isBehind (bzVec2 target) {return isBehind (target, -0.707f);}; + + bool isAhead (bzVec2 target, float cosThreshold) + { + bzVec2 targetDirection = target - m_position; + targetDirection.normalize(); + return bzDot(m_forward, targetDirection) > cosThreshold; + } + + bool isAside (bzVec2 target, float cosThreshold) + { + bzVec2 targetDirection = target - m_position; + targetDirection.normalize(); + float dp = bzDot(m_forward, targetDirection); + return (dp < cosThreshold) && (dp > -cosThreshold); + } + + bool isBehind (bzVec2 target, float cosThreshold) + { + bzVec2 targetDirection = target - m_position; + targetDirection.normalize(); + return bzDot(m_forward, targetDirection) < cosThreshold; + } + + private: + + Ship m_ship; + + bzVec2 m_position; + bzVec2 m_velocity; + bzVec2 m_up; + bzVec2 m_side; + bzVec2 m_forward; + + float m_speed = 0; + float m_maxForce = 0; + + // Wander behavior + float m_wanderSide; + float m_wanderUp; +} diff -r 82efafc87d54 -r 7f74e064dad5 ai/utilities.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ai/utilities.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * http://www.dsource.org/projects/openmelee + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.ai.utilities; + +import tango.math.random.Kiss : Kiss; + +float scalarRandomWalk(float initial, float walkspeed, float min, float max) { + + float next = initial + (((randomRange(0, 1) * 2) - 1) * walkspeed); + if (next < min) return min; + if (next > max) return max; + return next; +} + +// ---------------------------------------------------------------------------- +// classify a value relative to the interval between two bounds: +// returns -1 when below the lower bound +// returns 0 when between the bounds (inside the interval) +// returns +1 when above the upper bound +int intervalComparison(float x, float lowerBound, float upperBound) +{ + if (x < lowerBound) return -1; + if (x > upperBound) return +1; + return 0; +} + +T randomRange(T = int) (T min, T max) +{ + return min + Kiss.instance.natural() % (max + 1 - min); +} diff -r 82efafc87d54 -r 7f74e064dad5 boundaryListener.d --- a/boundaryListener.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2009, Mason Green (zzzzrrr) - * Based on Box2D by Erin Catto, http://www.box2d.org - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the polygonal nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -module openmelee.boundaryListener; - -import openmelee.melee; - -// bzWorld boundary callback -class BoundaryListener : bzBoundaryListener -{ - Melee melee; - - this(Melee melee) - { - this.melee = melee; - } - - void violation(bzBody rBody) - { - melee.boundaryViolated(rBody); - } -} diff -r 82efafc87d54 -r 7f74e064dad5 build-dmd-win.bat --- a/build-dmd-win.bat Tue Mar 24 16:47:42 2009 -0400 +++ b/build-dmd-win.bat Wed Mar 25 11:28:25 2009 -0400 @@ -1,4 +1,3 @@ -jake -I.. -I../blaze -I../xf/ext zlib.lib -inline -release -O main.d -::rebuild -I.. -I../blaze -I../xf/ext zlib.lib -inline -release -O main.d -::xfBuild main.d -oMain.exe -- -I.. -I../blaze -I../xf/ext zlib.lib -inline -release -O +jake -I.. -I../blaze -I../xf/ext zlib.lib -inline -release -O openmelee.d +::rebuild -I.. -I../blaze -I../xf/ext zlib.lib -inline -release -O openmelee.d diff -r 82efafc87d54 -r 7f74e064dad5 contactListener.d --- a/contactListener.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2009, Mason Green (zzzzrrr) - * Based on Box2D by Erin Catto, http://www.box2d.org - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the polygonal nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -module openmelee.contactListener; - -import openmelee.melee; - -// bzWorld contact callback -class ContactListener : bzContactListener -{ - - Melee melee; - - this(Melee melee) { - this.melee = melee; - } - - void add(bzContactPoint point) - { - if (melee.pointCount == k_maxContactPoints) { - return; - } - - ContactPoint *cp = &melee.points[melee.pointCount]; - cp.shape1 = point.shape1; - cp.shape2 = point.shape2; - cp.position = point.position; - cp.normal = point.normal; - cp.id = point.id; - cp.state = ContactState.e_contactAdded; - - ++melee.pointCount; - } - - void persist(bzContactPoint point) - { - if (melee.pointCount == k_maxContactPoints) { - return; - } - - ContactPoint *cp = &melee.points[melee.pointCount]; - cp.shape1 = point.shape1; - cp.shape2 = point.shape2; - cp.position = point.position; - cp.normal = point.normal; - cp.id = point.id; - cp.state = ContactState.e_contactPersisted; - - ++melee.pointCount; - } - - void remove(bzContactPoint point) - { - if (melee.pointCount == k_maxContactPoints) { - return; - } - - ContactPoint *cp = &melee.points[melee.pointCount]; - cp.shape1 = point.shape1; - cp.shape2 = point.shape2; - cp.position = point.position; - cp.normal = point.normal; - cp.id = point.id; - cp.state = ContactState.e_contactRemoved; - - ++melee.pointCount; - } - - void result(bzContactResult point) {} - -} diff -r 82efafc87d54 -r 7f74e064dad5 example.d --- a/example.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -// jake -I../minid -I.. -version=old example.d -module example; - -import xf.xpose2.Expose; -import xf.xpose2.MiniD; -import tango.text.convert.Format; - -struct vec3 { - float x, y, z; - - char[] toString() { - return Format("x={} y={} z={}", x, y, z); - } - - mixin(xpose2(` - .* - toString - _ctor overload vec3 function(float, float, float) - `)); - mixin xposeMiniD; -} - -class Poop { - int x = 0; - - this() { - this.x = 123456; - } - - this(int x) { - this.x = x; - } - - this (char[] zomg) { - this.x = zomg.length; - } - - int max(int a, int b) { - return a > b ? a : b; - } - - int dmax(int a, int b) { - return max(max(a, b), x); - } - - int dmax(int a, int b, int c) { - return dmax(a, dmax(b, c)); - } - - vec3 getVec3(int x, int y, int z) { - return vec3(x, y, z); - } - -} - -mixin(xpose2(`Poop`,` - dmax - dmax overload int function(int, int, int) ; md { rename "dmax2" } - getVec3 - .* - _ctor - _ctor overload Poop function(int) - _ctor overload Poop function(char[]) -`)); - -mixin xposeMiniD!(`Poop`); - -void main(char[][] args) -{ - MDVM vm; - auto t = openVM(&vm); - loadStdlibs(t); - xposeMiniD_initAll(t); - superPush(t, new Poop(10)); - newGlobal(t, "poop"); - importModule(t, args[1]); - lookup(t, "poop"); - auto poop = superGet!(Poop)(t, -1); - Stdout.formatln("poop.dmax(1, 2) == {}", poop.dmax(1, 2)); -} diff -r 82efafc87d54 -r 7f74e064dad5 game.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/game.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * http://www.dsource.org/projects/openmelee + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.game; + +import openmelee.melee.melee; + +class Game +{ + Melee melee; + + this() { + melee = new Melee; + } + + void run() { + melee.init(); + } + +} diff -r 82efafc87d54 -r 7f74e064dad5 main.d --- a/main.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2009, Mason Green (zzzzrrr) - * http://www.dsource.org/projects/openmelee - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the polygonal nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -module openmelee.main; - -import tango.io.Stdout : Stdout; - -version(distrib) import tango.io.vfs.ZipFolder; -import tango.time.StopWatch; -import fc = tango.text.convert.Float : toString; -import tango.util.log.Trace; -import tango.math.Math; - -import xf.core.JobHub; -import xf.hybrid.Hybrid; -import xf.hybrid.backend.GL; -import xf.omg.core.LinearAlgebra; - -import blaze.common.bzMath: bzVec2; - -import openmelee.melee; -import openmelee.render; -import openmelee.ai; - -const ITERS_PER_SECOND = 100; - -void main() { - - Settings settings; - float timeStep = settings.hz > 0.0f ? 1.0f / settings.hz : 0.0f; - version(distrib) gui.vfs.mount(new ZipFolder("./gui.zip")); - scope cfg = loadHybridConfig("./gui.cfg"); - scope renderer = new Renderer; - auto whut = new Render(&settings); - auto ai = new AI(whut.ship2); - - gui.begin(cfg).retained; - gui.push(`main`); - GLViewport(`glview`).renderingHandler(&whut.draw) - .addHandler(&whut.onClick) - .addHandler(&whut.onMove) - .addHandler(&whut.onKey) - .addHandler(&whut.onDT) - .addHandler(&whut.onMouseEnter) - .addHandler(&whut.onMouseLeave) - .grabKeyboardFocus; - gui.pop(); - gui.immediate.end; - - StopWatch timer; - - jobHub.addRepeatableJob( { - // Update physics - whut.world.step(timeStep, settings.velocityIterations, - settings.positionIterations); - }, ITERS_PER_SECOND); - - bool running = true; - - jobHub.addPreFrameJob( { - // Update AI - ai.move(whut.ship1); - }); - - jobHub.addPostFrameJob( { - - // Limit velocity - whut.ship1.limitVelocity(); - whut.ship2.limitVelocity(); - whut.ship1.updateState(); - whut.ship2.updateState(); - - gui.begin(cfg); - gui.push(`main`); - if (gui().getProperty!(bool)("frame.closeClicked")) { - running = false; - } - - - if(whut.thrust) { - whut.ship1.thrust(); - } - - gui().setProperty!(bool)("showCursor", true); - gui.pop(); - gui.end; - gui.render(renderer); - - }); - - while (running && !whut.quit) { - float delta = timer.stop; - timer.start; - jobHub.update(delta); - } -} diff -r 82efafc87d54 -r 7f74e064dad5 melee.d --- a/melee.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,320 +0,0 @@ -/* - * Copyright (c) 2009, Mason Green (zzzzrrr) - * http://www.dsource.org/projects/openmelee - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the polygonal nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -module openmelee.melee; - -import tango.io.Stdout: Stdout; - -import Integer = tango.text.convert.Integer; -import tango.math.Math; - -import xf.hybrid.Event; -import xf.input.KeySym; -import xf.omg.core.LinearAlgebra; - -public import blaze.all; - -import openmelee.boundaryListener; -import openmelee.contactListener; -import openmelee.ship; -import openmelee.urQuan; -import openmelee.orz; -import openmelee.planet; - -// Cursor scale factor -const CURSORSIZE = 0.05f; - -const INIT_SPAWN_SIZE = 0.5f; - -// Dragging stuffs -const BUNGEE_K = 1.5f; -// Damping factor for dragging -const DRAGDAMP = 20.0f; - -// Size of hinges -const HINGE_RADIUS = 0.05f; - -// Smallest allowed dimension -const MIN_DIMENSION = 0.1; - -const k_maxContactPoints = 2048; - -enum ContactState { - e_contactAdded, - e_contactPersisted, - e_contactRemoved -} - -struct ContactPoint { - bzShape shape1; - bzShape shape2; - bzVec2 normal; - bzVec2 position; - bzVec2 velocity; - bzContactID id; - ContactState state; -} - -// Melee settings. Some can be controlled in the GUI. -struct Settings { - float hz = 60; - int velocityIterations = 3; - int positionIterations = 1; - bool drawShapes = true; - bool drawJoints = true; - bool drawControllers; - bool drawCoreShapes; - bool drawAABBs; - bool drawOBBs; - bool drawPairs; - bool drawContactPoints; - bool drawContactNormals; - bool drawContactForces; - bool drawFrictionForces; - bool drawCOMs; - bool drawStats; - bool enableWarmStarting; - bool enableTOI; -} - -// Dirty, dirty hack for communicating config changes to Main -// TODO: Harass h3 to add .changed to hybrid so this isn't necessary -struct ConfigChange (T) -{ - protected - { - bool _pending = false; - T _value; - } - - T value() - { - _pending = false; - return _value; - } - - void value(T change) - { - _value = change; - _pending = true; - } - - bool pending() - { - return _pending; - } - - T opAssign(T change) - { - value(change); - return _value; - } - - bool opEquals(T other) - { - return _value == other; - } -} - -class Melee -{ - - this(Settings *settings) - { - this.settings = settings; - spawnRect = vec2(INIT_SPAWN_SIZE, INIT_SPAWN_SIZE); - // bzWorld boundary callback - m_boundaryListener = new BoundaryListener(this); - // bzContact callback - m_contactListener = new ContactListener(this); - init(); - } - - void init() { - // Define world boundaries - worldAABB.lowerBound.set(-400.0f, -250.0f); - worldAABB.upperBound.set(400.0f, 250.0f); - world = new bzWorld(worldAABB, gravity, allowSleep); - world.boundaryListener = m_boundaryListener; - world.contactListener = m_contactListener; - viewCenter = vec2(10, 10); - ship1 = new UrQuan(world); - ship2 = new Orz(world); - ship2.rBody.angle = 3.14159265/4; - auto planet = new Planet(world); - } - - void drag() - { - - } - - EventHandling onClick(MouseButtonEvent e) - { - return EventHandling.Stop; - } - - EventHandling onKey(KeyboardEvent e) - { - // Key pressed - if (e.down) { - switch (e.keySym) { - case KeySym.space: - settings.drawAABBs = !settings.drawAABBs; - break; - case KeySym.Escape: - quit = true; - break; - case KeySym.Up: - thrust = true; - break; - case KeySym.Left: - ship1.turnLeft(); - break; - case KeySym.Right: - ship1.turnRight(); - break; - case KeySym.Down: - break; - default: - break; - } - // Key released - } else { - if(e.keySym == KeySym.Up) { - thrust = false; - } else if (e.keySym == KeySym.Left || e.keySym == KeySym.Right) { - ship1.rBody.angularVelocity = 0.0f; - } - } - return EventHandling.Stop; - } - - // Mouse move - EventHandling onMove(MouseMoveEvent e) - { - return EventHandling.Stop; - } - - EventHandling onDT(TimeUpdateEvent e) - { - return EventHandling.Continue; - } - - EventHandling onMouseEnter(MouseEnterEvent e) - { - return EventHandling.Continue; - } - - EventHandling onMouseLeave(MouseLeaveEvent e) - { - return EventHandling.Continue; - } - - protected - { - const bzVec2 gravity = bzVec2(0.0f, 0.0f); - bool allowSleep = false; - - vec2 spawnRect; - - vec2[] drawing; - - vec2i screenSize = vec2i.zero; - vec2 mousePos = vec2.zero; - - bool scaling = false; - bool full = false; - - vec2 spawnStart; - - bool preserveBullet = false; - - float waterDelta = 0; - } - - void boundaryViolated(bzBody rBody) - { - float x,y; - - if(rBody.position.x > worldAABB.upperBound.x) { - x = worldAABB.lowerBound.x + 5; - rBody.position = bzVec2(x, rBody.position.y); - } else if (rBody.position.x < worldAABB.lowerBound.x) { - x = worldAABB.upperBound.x - 5; - rBody.position = bzVec2(x, rBody.position.y); - } else if (rBody.position.y > worldAABB.upperBound.y) { - y = worldAABB.lowerBound.y + 5; - rBody.position = bzVec2(rBody.position.x, y); - } else if(rBody.position.y < worldAABB.lowerBound.y) { - y = worldAABB.upperBound.y - 5; - rBody.position = bzVec2(rBody.position.x, y); - } - } - - bool quit; - - // Ortho view zoom - float zoom = 40; - int pointCount; - vec2 viewCenter; - - bzWorld world; - Settings *settings; - - // bzWorld boundary listener. Destroy bodies that leave world bzAABB - bzBoundaryListener m_boundaryListener; - bzContactListener m_contactListener; - ContactPoint[k_maxContactPoints] points; - - ConfigChange!(vec2) editChange; - bool thrust; - bzAABB worldAABB; - - Ship ship1; - Ship ship2; -} - -// Utility functions -bzVec2 toBlaze(vec2 vec) -{ - auto ret = bzVec2(vec.x, vec.y); - return ret; -} - -vec2 rotate(vec2 point, float rad) -{ - return vec2(cos(rad) * point.x - sin(rad) * point.y, sin(rad) * point.x + cos(rad) * point.y); -} - -class Select -{ - bool select; -} diff -r 82efafc87d54 -r 7f74e064dad5 melee/boundaryListener.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/melee/boundaryListener.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * Based on Box2D by Erin Catto, http://www.box2d.org + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.melee.boundaryListener; + +import blaze.dynamics.bzWorldCallbacks : bzBoundaryListener; +import blaze.dynamics.bzBody : bzBody; + +import openmelee.melee.melee; + +// bzWorld boundary callback +class BoundaryListener : bzBoundaryListener +{ + Melee melee; + + this(Melee melee) + { + this.melee = melee; + } + + void violation(bzBody rBody) + { + melee.boundaryViolated(rBody); + } +} diff -r 82efafc87d54 -r 7f74e064dad5 melee/contactListener.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/melee/contactListener.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * Based on Box2D by Erin Catto, http://www.box2d.org + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.melee.contactListener; + +import blaze.collision.bzCollision : bzContactID; +import blaze.dynamics.contact.bzContact : bzContactPoint, bzContactResult; +import blaze.dynamics.bzWorldCallbacks : bzContactListener; +import blaze.collision.shapes.bzShape : bzShape; +import blaze.common.bzMath : bzVec2; + +import openmelee.melee.melee; + +enum ContactState { + e_contactAdded, + e_contactPersisted, + e_contactRemoved +} + +struct ContactPoint { + bzShape shape1; + bzShape shape2; + bzVec2 normal; + bzVec2 position; + bzVec2 velocity; + bzContactID id; + ContactState state; +} + +// bzWorld contact callback +class ContactListener : bzContactListener +{ + + Melee melee; + + this(Melee melee) { + this.melee = melee; + } + + void add(bzContactPoint point) + { + if (melee.pointCount == k_maxContactPoints) { + return; + } + + ContactPoint *cp = &melee.points[melee.pointCount]; + cp.shape1 = point.shape1; + cp.shape2 = point.shape2; + cp.position = point.position; + cp.normal = point.normal; + cp.id = point.id; + cp.state = ContactState.e_contactAdded; + + ++melee.pointCount; + } + + void persist(bzContactPoint point) + { + if (melee.pointCount == k_maxContactPoints) { + return; + } + + ContactPoint *cp = &melee.points[melee.pointCount]; + cp.shape1 = point.shape1; + cp.shape2 = point.shape2; + cp.position = point.position; + cp.normal = point.normal; + cp.id = point.id; + cp.state = ContactState.e_contactPersisted; + + ++melee.pointCount; + } + + void remove(bzContactPoint point) + { + if (melee.pointCount == k_maxContactPoints) { + return; + } + + ContactPoint *cp = &melee.points[melee.pointCount]; + cp.shape1 = point.shape1; + cp.shape2 = point.shape2; + cp.position = point.position; + cp.normal = point.normal; + cp.id = point.id; + cp.state = ContactState.e_contactRemoved; + + ++melee.pointCount; + } + + void result(bzContactResult point) {} + +} diff -r 82efafc87d54 -r 7f74e064dad5 melee/melee.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/melee/melee.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * http://www.dsource.org/projects/openmelee + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.melee.melee; + +import tango.io.Stdout; + +version(distrib) import tango.io.vfs.ZipFolder; +import tango.time.StopWatch; +import fc = tango.text.convert.Float : toString; +import tango.util.log.Trace; + +import xf.core.JobHub; +import xf.hybrid.Hybrid; +import xf.hybrid.backend.GL; + +import blaze.common.bzMath : bzVec2; +import blaze.bzWorld : bzWorld; +import blaze.collision.bzCollision : bzAABB; + +import openmelee.melee.boundaryListener; +import openmelee.melee.contactListener; +import openmelee.render.render; +import openmelee.ai.ai; +import openmelee.ai.human; +import openmelee.ships.urQuan; +import openmelee.ships.orz; +import openmelee.ships.planet; + +const ITERS_PER_SECOND = 100; +const k_maxContactPoints = 100; + +// Melee settings +struct Settings { + float hz = 60; + int velocityIterations = 3; + int positionIterations = 1; + bool drawShapes = true; + bool drawJoints = true; + bool drawControllers; + bool drawCoreShapes; + bool drawAABBs; + bool drawOBBs; + bool drawPairs; + bool drawContactPoints; + bool drawContactNormals; + bool drawContactForces; + bool drawFrictionForces; + bool drawCOMs; + bool drawStats; + bool enableWarmStarting; + bool enableTOI; +} + +class Melee { + + Settings settings; + float timeStep; + const bzVec2 gravity = bzVec2(0.0f, 0.0f); + bool allowSleep; + Render draw; + + AI ai; + Human human; + Ship ship1; + Ship ship2; + + bool running; + + StopWatch timer; + bzAABB worldAABB; + bzWorld world; + bzBoundaryListener m_boundaryListener; + bzContactListener m_contactListener; + ContactPoint[k_maxContactPoints] points; + int pointCount; + + this() { + } + + void init() { + + timeStep = settings.hz > 0.0f ? 1.0f / settings.hz : 0.0f; + version(distrib) gui.vfs.mount(new ZipFolder("./gui.zip")); + scope cfg = loadHybridConfig("./gui.cfg"); + scope renderer = new Renderer; + + m_boundaryListener = new BoundaryListener(this); + m_contactListener = new ContactListener(this); + initWorld(); + running = true; + + draw = new Render(world, ship1, ship2, settings); + human = new Human(ship1); + ai = new AI(ship2); + + gui.begin(cfg).retained; + gui.push(`main`); + GLViewport(`glview`).renderingHandler(&draw.draw) + .addHandler(&human.onClick) + .addHandler(&human.onMove) + .addHandler(&human.onKey) + .addHandler(&human.onDT) + .addHandler(&human.onMouseEnter) + .addHandler(&human.onMouseLeave) + .grabKeyboardFocus; + gui.pop(); + gui.immediate.end; + + jobHub.addRepeatableJob( { + // Update physics + world.step(timeStep, settings.velocityIterations, settings.positionIterations); + }, ITERS_PER_SECOND); + + jobHub.addPreFrameJob( { + // Update AI + ai.move(ship1); + }); + + jobHub.addPostFrameJob( { + + // Limit velocity + ship1.limitVelocity(); + ship2.limitVelocity(); + ship1.updateState(); + ship2.updateState(); + + gui.begin(cfg); + gui.push(`main`); + if (gui().getProperty!(bool)("frame.closeClicked")) { + running = false; + } + + if(human.thrust) { + ship1.thrust(); + } + + gui().setProperty!(bool)("showCursor", true); + gui.pop(); + gui.end; + gui.render(renderer); + + }); + + while (running && !human.quit) { + float delta = timer.stop; + timer.start; + jobHub.update(delta); + } + } + + void initWorld() { + // Define world boundaries + worldAABB.lowerBound.set(-400.0f, -250.0f); + worldAABB.upperBound.set(400.0f, 250.0f); + world = new bzWorld(worldAABB, gravity, allowSleep); + world.boundaryListener = m_boundaryListener; + world.contactListener = m_contactListener; + ship1 = new UrQuan(world); + ship2 = new Orz(world); + ship2.rBody.angle = 3.14159265/4; + auto planet = new Planet(world); + } + + void boundaryViolated(bzBody rBody) + { + float x,y; + + if(rBody.position.x > worldAABB.upperBound.x) { + x = worldAABB.lowerBound.x + 5; + rBody.position = bzVec2(x, rBody.position.y); + } else if (rBody.position.x < worldAABB.lowerBound.x) { + x = worldAABB.upperBound.x - 5; + rBody.position = bzVec2(x, rBody.position.y); + } else if (rBody.position.y > worldAABB.upperBound.y) { + y = worldAABB.lowerBound.y + 5; + rBody.position = bzVec2(rBody.position.x, y); + } else if(rBody.position.y < worldAABB.lowerBound.y) { + y = worldAABB.upperBound.y - 5; + rBody.position = bzVec2(rBody.position.x, y); + } + } +} diff -r 82efafc87d54 -r 7f74e064dad5 models.d --- a/models.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,239 +0,0 @@ -void spathiEluder(inout bzVec2[][] bodyVertex, inout bzVec2[][] vertex) -{ - vertex.length = bodyVertex.length = 11; - - vertex[0].length = bodyVertex[0].length = 19; - // Hull - bodyVertex[0][0] = bzVec2(2.24,31.54); - bodyVertex[0][1] = bzVec2(14.14,28.28); - bodyVertex[0][2] = bzVec2(23.89,20.72); - bodyVertex[0][3] = bzVec2(30.00,10.00); - bodyVertex[0][4] = bzVec2(31.54, -2.24); - bodyVertex[0][5] = bzVec2(28.28,-14.14); - bodyVertex[0][6] = bzVec2(22.48,-21.62); - bodyVertex[0][7] = bzVec2(20.72,-23.89); - bodyVertex[0][8] = bzVec2(10.00,-30.00); - bodyVertex[0][9] = bzVec2(-2.24,-31.54); - bodyVertex[0][10] = bzVec2(-8.19,-29.91); - bodyVertex[0][11] = bzVec2(-19.02,-24.50); - bodyVertex[0][12] = bzVec2(-23.89,-20.72); - bodyVertex[0][13] = bzVec2(-30.00,-10.00); - bodyVertex[0][14] = bzVec2(-31.00,-5.00); - bodyVertex[0][15] = bzVec2(-31.00,5.00); - bodyVertex[0][16] = bzVec2(-28.28,14.14); - bodyVertex[0][17] = bzVec2(-20.72,23.89); - bodyVertex[0][18] = bzVec2(-10.00,30.00); - - vertex[1].length = bodyVertex[1].length = 4; - // Body - bodyVertex[1][0] = bzVec2(14.14,28.28); - bodyVertex[1][1] = bzVec2(23.89,20.72); - bodyVertex[1][2] = bzVec2(44.56,47.70); - bodyVertex[1][3] = bzVec2(35.97,54.29); - - vertex[2].length = bodyVertex[2].length = 4; - // Top Strut - bodyVertex[2][0] = bzVec2(22.48,-21.62); - bodyVertex[2][1] = bzVec2(28.28,-14.14); - bodyVertex[2][2] = bzVec2(53.41,-29.39); - bodyVertex[2][3] = bzVec2(46.67,-37.86); - - vertex[3].length = bodyVertex[3].length = 4; - // Top Wing - bodyVertex[3][0] = bzVec2(-19.02,-24.50); - bodyVertex[3][1] = bzVec2(-8.19,-29.91); - bodyVertex[3][2] = bzVec2(-36.26,-62.25); - bodyVertex[3][3] = bzVec2(-42.85,-53.66); - - vertex[4].length = bodyVertex[4].length = 4; - // Bottom Strut - bodyVertex[4][0] = bzVec2(-31.00,-5.00); - bodyVertex[4][1] = bzVec2(-31.00,5.00); - bodyVertex[4][2] = bzVec2(-46.00,5.00); - bodyVertex[4][3] = bzVec2(-46.00,-5.00); - - vertex[5].length = bodyVertex[5].length = 4; - // Bottom Wing - bodyVertex[5][0] = bzVec2(-10.00,30.00); - bodyVertex[5][1] = bzVec2(-20.72,23.89); - bodyVertex[5][2] = bzVec2(-50.00,65.86); - bodyVertex[5][3] = bzVec2(-40.00,70.00); - - vertex[6].length = bodyVertex[6].length = 8; - // Rear, top Pod - bodyVertex[6][0] = bzVec2(-40.00 ,70.00); - bodyVertex[6][1] = bzVec2(-35.86 , 80.00); - bodyVertex[6][2] = bzVec2( -40.00, 90.00); - bodyVertex[6][3] = bzVec2( -50.00,94.14); - bodyVertex[6][4] = bzVec2( -60.00, 90.00); - bodyVertex[6][5] = bzVec2(-64.14 , 80.00); - bodyVertex[6][6] = bzVec2(-60.00 , 70.00); - bodyVertex[6][7] = bzVec2(-50.00 ,65.86); - - vertex[7].length = bodyVertex[7].length = 8; - // Rear, middle pod - bodyVertex[7][0] = bzVec2(-46.00,5.00); - bodyVertex[7][1] = bzVec2( -46.00,-5.00); - bodyVertex[7][2] = bzVec2(-54.47 ,-12.02); - bodyVertex[7][3] = bzVec2( -65.30, -13.11); - bodyVertex[7][4] = bzVec2( -73.02, -5.53); - bodyVertex[7][5] = bzVec2( -73.11,5.30); - bodyVertex[7][6] = bzVec2( -65.53, 13.02); - bodyVertex[7][7] = bzVec2( -54.70,13.11); - - - vertex[8].length = bodyVertex[8].length = 8; - // Rear, bottom pod - bodyVertex[8][0] = bzVec2( -36.26,-62.25); - bodyVertex[8][1] = bzVec2( -42.85,-53.66); - bodyVertex[8][2] = bzVec2( -53.59,-52.25); - bodyVertex[8][3] = bzVec2( -62.17,-58.84); - bodyVertex[8][4] = bzVec2( -63.59,-69.57); - bodyVertex[8][5] = bzVec2( -57.00,-78.16); - bodyVertex[8][6] = bzVec2( -46.26,-79.57); - bodyVertex[8][7] = bzVec2( -37.68,-72.98); - - vertex[9].length = bodyVertex[9].length = 8; - - bodyVertex[9][0] = bzVec2( 53.41, -29.39); - bodyVertex[9][1] = bzVec2( 46.67,-37.86); - bodyVertex[9][2] = bzVec2( 47.89,-47.61); - bodyVertex[9][3] = bzVec2( 56.36, -55.35); - bodyVertex[9][4] = bzVec2( 67.12,-54.12); - bodyVertex[9][5] = bzVec2( 73.86, -45.65); - bodyVertex[9][6] = bzVec2( 72.63,-34.90); - bodyVertex[9][7] = bzVec2( 64.16,-28.16); - - vertex[10].length = bodyVertex[10].length = 8; - - bodyVertex[10][0] = bzVec2( 35.97, 54.29); - bodyVertex[10][1] = bzVec2( 44.56, 47.70); - bodyVertex[10][2] = bzVec2( 56.29, 49.12 ); - bodyVertex[10][3] = bzVec2( 61.88, 57.70); - bodyVertex[10][4] = bzVec2( 60.47, 68.44); - bodyVertex[10][5] = bzVec2( 51.88, 75.02); - bodyVertex[10][6] = bzVec2( 41.15, 73.61); - bodyVertex[10][7] = bzVec2( 34.56, 65.02); -} - -void urQuanDreadnought(inout bzVec2[][] bodyVertex, inout bzVec2[][] vertex) -{ - vertex.length = bodyVertex.length = 6; - - vertex[0].length = bodyVertex[0].length = 8; - // Head - bodyVertex[0][0] = bzVec2(42,49); - bodyVertex[0][1] = bzVec2(63,49); - bodyVertex[0][2] = bzVec2(70,45.5); - bodyVertex[0][3] = bzVec2(73.5,38.5); - bodyVertex[0][4] = bzVec2(73.5,-42); - bodyVertex[0][5] = bzVec2(70,-49); - bodyVertex[0][6] = bzVec2(63,-56); - bodyVertex[0][7] = bzVec2(42,-56); - - vertex[1].length = bodyVertex[1].length = 4; - // Body - bodyVertex[1][0] = bzVec2(-70,-28); - bodyVertex[1][1] = bzVec2(-70,24.5); - bodyVertex[1][2] = bzVec2(42,24.5); - bodyVertex[1][3] = bzVec2(42,-31.5); - - vertex[2].length = bodyVertex[2].length = 4; - // Top Strut - bodyVertex[2][0] = bzVec2(0,24.5); - bodyVertex[2][1] = bzVec2(-28,24.5); - bodyVertex[2][2] = bzVec2(-28,42); - bodyVertex[2][3] = bzVec2(0,42); - - vertex[3].length = bodyVertex[3].length = 4; - // Top Wing - bodyVertex[3][0] = bzVec2(-70,42); - bodyVertex[3][1] = bzVec2(-49,63); - bodyVertex[3][2] = bzVec2(28,63); - bodyVertex[3][3] = bzVec2(28,42); - - vertex[4].length = bodyVertex[4].length = 4; - // Bottom Strut - bodyVertex[4][0] = bzVec2(0,-31.5); - bodyVertex[4][1] = bzVec2(0,-49); - bodyVertex[4][2] = bzVec2(-28,-49); - bodyVertex[4][3] = bzVec2(-28,-31.5); - - vertex[5].length = bodyVertex[5].length = 4; - // Bottom Wing - bodyVertex[5][0] = bzVec2(-70,-49); - bodyVertex[5][1] = bzVec2(28,-49); - bodyVertex[5][2] = bzVec2(28,-70); - bodyVertex[5][3] = bzVec2(-42,-70); -} - -void yehatTerminator(inout bzVec2[][] bodyVertex, inout bzVec2[][] vertex) -{ - vertex.length = bodyVertex.length = 4; - vertex[0].length = bodyVertex[0].length = 3; - // Cockpit - bodyVertex[0][0] = bzVec2(-14,21); - bodyVertex[0][1] = bzVec2(0,42); - bodyVertex[0][2] = bzVec2(14,21); - - - vertex[1].length = bodyVertex[1].length = 4; - // Body - bodyVertex[1][0] = bzVec2(-14,21); - bodyVertex[1][1] = bzVec2(-14,-21); - bodyVertex[1][2] = bzVec2(14,-21); - bodyVertex[1][3] = bzVec2(14,21); - - vertex[2].length = bodyVertex[2].length = 4; - // Right Wing - bodyVertex[2][0] = bzVec2(14,21); - bodyVertex[2][1] = bzVec2(14,-21); - bodyVertex[2][2] = bzVec2(70,0); - bodyVertex[2][3] = bzVec2(84,59.5); - - vertex[3].length = bodyVertex[3].length = 4; - // Left Wing - bodyVertex[3][0] = bzVec2(-14,21); - bodyVertex[3][1] = bzVec2(-14,-21); - bodyVertex[3][2] = bzVec2(-70,0); - bodyVertex[3][3] = bzVec2(-84,59.5); -} - -void orzNemesis(inout bzVec2[][] bodyVertex, inout bzVec2[][] vertex) -{ - vertex.length = bodyVertex.length = 3; - vertex[0].length = bodyVertex[0].length = 4; - // Body - bodyVertex[0][0] = bzVec2(-28,21); - bodyVertex[0][1] = bzVec2(-28,-28); - bodyVertex[0][2] = bzVec2(42,-21); - bodyVertex[0][3] = bzVec2(42,14); - - vertex[1].length = bodyVertex[1].length = 5; - // Top Wing - bodyVertex[1][0] = bzVec2(-28,21); - bodyVertex[1][1] = bzVec2(-70,63); - bodyVertex[1][2] = bzVec2(-49,63); - bodyVertex[1][3] = bzVec2(70,14); - bodyVertex[1][4] = bzVec2(42,14); - - vertex[2].length = bodyVertex[2].length = 5; - // Bottom Wing - bodyVertex[2][0] = bzVec2(-28,-28); - bodyVertex[2][1] = bzVec2(-70,-63); - bodyVertex[2][2] = bzVec2(-49,-63); - bodyVertex[2][3] = bzVec2(70,-21); - bodyVertex[2][4] = bzVec2(42,-21); -} - -void triangle(inout bzVec2[][] bodyVertex, inout bzVec2[][] vertex) -{ - - vertex.length = bodyVertex.length = 1; - vertex[0].length = bodyVertex[0].length = 3; - - bodyVertex[0][0] = bzVec2(0.0f,7.0f); - bodyVertex[0][1] = bzVec2(7.0f,-7.0f); - bodyVertex[0][2] = bzVec2(-7.0f,-7.0f); - -} diff -r 82efafc87d54 -r 7f74e064dad5 openmelee.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openmelee.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * http://www.dsource.org/projects/openmelee + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.openmelee; + +import openmelee.game; + +void main(char[][] args) { + + auto game = new Game(); + game.run(); + +} diff -r 82efafc87d54 -r 7f74e064dad5 openmelee.geany --- a/openmelee.geany Tue Mar 24 16:47:42 2009 -0400 +++ b/openmelee.geany Wed Mar 25 11:28:25 2009 -0400 @@ -14,17 +14,17 @@ run_cmd= [files] -current_page=0 -FILE_NAME_0=3305;D;0;16;0;1;1;C:\\workspace\\openmelee\\main.d;0 -FILE_NAME_1=1783;D;0;16;0;1;1;C:\\workspace\\openmelee\\melee.d;0 +current_page=1 +FILE_NAME_0=3173;D;0;16;0;1;1;C:\\workspace\\openmelee\\main.d;0 +FILE_NAME_1=7284;D;0;16;0;1;1;C:\\workspace\\openmelee\\melee.d;0 FILE_NAME_2=2250;D;0;16;0;1;1;C:\\workspace\\openmelee\\orz.d;0 -FILE_NAME_3=9747;D;0;16;0;1;1;C:\\workspace\\openmelee\\render.d;0 -FILE_NAME_4=2659;D;0;16;0;1;1;C:\\workspace\\openmelee\\ship.d;0 +FILE_NAME_3=9310;D;0;16;0;1;1;C:\\workspace\\openmelee\\render.d;0 +FILE_NAME_4=4052;D;0;16;0;1;1;C:\\workspace\\openmelee\\ship.d;0 FILE_NAME_5=6206;D;0;16;0;1;1;C:\\workspace\\openmelee\\steer.d;0 FILE_NAME_6=2252;D;0;16;0;1;1;C:\\workspace\\openmelee\\urQuan.d;0 FILE_NAME_7=0;None;0;16;0;1;1;C:\\workspace\\openmelee\\build-dmd-win.bat;0 FILE_NAME_8=304;Conf;0;16;0;1;0;C:\\workspace\\openmelee\\gui.cfg;0 FILE_NAME_9=1648;D;0;16;0;1;0;C:\\workspace\\openmelee\\planet.d;0 -FILE_NAME_10=2827;D;0;16;0;1;1;C:\\workspace\\openmelee\\ai.d;0 +FILE_NAME_10=2757;D;0;16;0;1;1;C:\\workspace\\openmelee\\ai.d;0 FILE_NAME_11=814;D;0;16;0;1;1;C:\\workspace\\openmelee\\example.d;0 FILE_NAME_12=19;None;0;16;0;1;1;C:\\workspace\\openmelee\\testScript.md;0 diff -r 82efafc87d54 -r 7f74e064dad5 orz.d --- a/orz.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2009, Mason Green (zzzzrrr) - * http://www.dsource.org/projects/openmelee - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the polygonal nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -module openmelee.orz; - -import blaze.dynamics.bzBody : bzBody; -import blaze.bzWorld: bzWorld; -import blaze.dynamics.bzBodyDef; -import blaze.collision.shapes.bzPolygon : bzPolyDef; -import blaze.common.bzMath: bzVec2, PI; - -import openmelee.ship; - -// UrQuan Dreadnought -class Orz : Ship -{ - - float scale = 0.025; - - this(bzWorld world) { - - super(world); - engineForce = bzVec2(500, 0); - turnForce = bzVec2(0, 5000); - rightTurnPoint = bzVec2(-0.5, 0); - leftTurnPoint = bzVec2(0.5, 0); - - auto bodyDef = new bzBodyDef; - //bodyDef.isBullet = true; - bodyDef.position = bzVec2(20,15); - bodyDef.angle = PI/2; - bodyDef.allowFreeze = false; - - rBody = world.createBody(bodyDef); - float density = 5.0f; - - // Body - auto b = new bzPolyDef(density); - b.vertices.length = 4; - b.vertices[0] = bzVec2(42,14) * scale; - b.vertices[1] = bzVec2(-28,21) * scale; - b.vertices[2] = bzVec2(-28,-28) * scale; - b.vertices[3] = bzVec2(42,-21) * scale; - shapes.add(rBody.createShape(b)); - - // Top Wing - auto tWing = new bzPolyDef(density); - tWing.vertices.length = 5; - tWing.vertices[4] = bzVec2(-28,21) * scale; - tWing.vertices[3] = bzVec2(-70,63) * scale; - tWing.vertices[2] = bzVec2(-49,63) * scale; - tWing.vertices[1] = bzVec2(70,14) * scale; - tWing.vertices[0] = bzVec2(42,14) * scale; - shapes.add(rBody.createShape(tWing)); - - // Bottom Wing - auto bWing = new bzPolyDef(density); - bWing.vertices.length = 5; - bWing.vertices[0] = bzVec2(-28,-28) * scale; - bWing.vertices[1] = bzVec2(-70,-63) * scale; - bWing.vertices[2] = bzVec2(-49,-63) * scale; - bWing.vertices[3] = bzVec2(70,-21) * scale; - bWing.vertices[4] = bzVec2(42,-21) * scale; - shapes.add(rBody.createShape(bWing)); - - rBody.setMassFromShapes(); - setPlanetGravity(); - } -} diff -r 82efafc87d54 -r 7f74e064dad5 planet.d --- a/planet.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2009, Mason Green (zzzzrrr) - * http://www.dsource.org/projects/openmelee - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the polygonal nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -module openmelee.planet; - -import blaze.dynamics.bzBody : bzBody; -import blaze.bzWorld: bzWorld; -import blaze.dynamics.bzBodyDef; -import blaze.collision.shapes.bzCircle : bzCircleDef; -import blaze.common.bzMath: bzVec2; - -class Planet -{ - - bzWorld world; - - this(bzWorld world) { - this.world = world; - init(); - } - - void init() { - // Create planet - bzVec2 position = bzVec2.zeroVect; - float angle = 0.0f; - auto bd = new bzBodyDef(position, angle); - auto rBody = world.createBody(bd); - float radius = 7.0f; - float density = 7.5f; - auto sd = new bzCircleDef(density, radius); - float friction = 1.0f; - float restitution = 0.1f; - sd.friction = friction; - sd.restitution = restitution; - rBody.createShape(sd); - } -} diff -r 82efafc87d54 -r 7f74e064dad5 render.d --- a/render.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,577 +0,0 @@ -/* - * Copyright (c) 2009, Mason Green (zzzzrrr) - * Based on Box2D by Erin Catto, http://www.box2d.org - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the polygonal nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -module openmelee.render; - -import xf.dog.Dog; -import xf.omg.core.LinearAlgebra; -import xf.hybrid.Event; -import xf.hybrid.Font; - -import openmelee.melee; - -// Water stuffs -const MAX_CIRCLE_RES = 32; - -/// Color for drawing. Each value has the range [0,1]. -struct Color { - static Color opCall(float r, float g, float b) - { - Color u; - u.r = r; - u.g = g; - u.b = b; - return u; - } - - float r = 0; - float g = 0; - float b = 0; -} - -class Render : Melee -{ - -this(Settings *settings) { - - super(settings); -} - -void drawCircle(GL gl, vec2 center, float radius, bool water = false, float theta = float.nan) -{ - int segs = cast(int)(radius) + 20; - if (segs > MAX_CIRCLE_RES) segs = MAX_CIRCLE_RES; - double coef = 2.0 * PI / segs; - - auto realTheta = (theta <>= 0 ? theta : 0); - if (water) { - gl.immediate(GL_TRIANGLE_FAN, - { - gl.Vertex2fv(center.ptr); - for (int n = 0; n <= segs; n++) { - double rads = n * coef; - gl.Vertex2f(radius * cos(rads + realTheta) + center.x, radius * sin(rads + realTheta) + center.y); - } - }); - } - - gl.immediate(GL_LINE_STRIP, - { - for (int n = 0; n <= segs; n++) { - double rads = n * coef; - gl.Vertex2f(radius * cos(rads + realTheta) + center.x, radius * sin(rads + realTheta) + center.y); - } - if (theta <>= 0) - gl.Vertex2fv(center.ptr); - }); -} - -void drawSolidCircle(GL gl, vec2 center, float radius, vec2 axis, Color color) -{ - const k_segments = 25.0f; - const k_increment = 2.0f * PI / k_segments; - float theta = 0.0f; - gl.Enable(GL_BLEND); - gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl.Color4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f); - gl.Begin(GL_TRIANGLE_FAN); - for (int i = 0; i < k_segments; ++i) { - vec2 v = center + radius * vec2(cos(theta), sin(theta)); - gl.Vertex2f(v.x, v.y); - theta += k_increment; - } - gl.End(); - gl.Disable(GL_BLEND); - - theta = 0.0f; - gl.Color4f(color.r, color.g, color.b, 1.0f); - gl.Begin(GL_LINE_LOOP); - for (int i = 0; i < k_segments; ++i) { - vec2 v = center + radius * vec2(cos(theta), sin(theta)); - gl.Vertex2f(v.x, v.y); - theta += k_increment; - } - gl.End(); - - vec2 p = center + radius * axis; - gl.Begin(GL_LINES); - gl.Vertex2f(center.x, center.y); - gl.Vertex2f(p.x, p.y); - gl.End(); -} - -void drawPolygon(GL gl, vec2[] glVerts, Color color) -{ - gl.Color3f(color.r, color.g, color.b); - gl.immediate(GL_LINE_LOOP, - { - foreach (v; glVerts) - gl.Vertex2fv(v.ptr); - }); -} - -void drawSolidPolygon(GL gl, vec2[] vertices, Color color) -{ - gl.Enable(GL_BLEND); - gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl.Color4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f); - gl.Begin(GL_TRIANGLE_FAN); - for (int i = 0; i < vertices.length; ++i) { - gl.Vertex2f(vertices[i].x, vertices[i].y); - } - gl.End(); - gl.Disable(GL_BLEND); - - gl.Color4f(color.r, color.g, color.b, 1.0f); - gl.Begin(GL_LINE_LOOP); - for (int i = 0; i < vertices.length; ++i) { - gl.Vertex2f(vertices[i].x, vertices[i].y); - } - gl.End(); -} - - -void drawPoint(GL gl, vec2 p, float size, Color color) -{ - gl.Color3f(color.r, color.g, color.b); - gl.PointSize(size); - gl.Begin(GL_POINTS); - gl.Vertex2f(p.x, p.y); - gl.End(); - gl.PointSize(1.0f); -} - -void drawSegment(GL gl, vec2 begin, vec2 end, Color color) -{ - gl.Color3f(color.r, color.g, color.b); - gl.immediate(GL_LINES, - { - gl.Vertex2fv(begin.ptr); - gl.Vertex2fv(end.ptr); - }); -} - -// TODO: handle inequal radii correctly -void connectCircles(GL gl, vec2 center1, float radius1, vec2 center2, float radius2) -{ - auto d = center2 - center1; - if (!d.length) - return; - d *= (d.length - radius1) / d.length; - center1 += d; - center2 -= d; - gl.immediate(GL_LINES, - { - gl.Vertex2fv(center1.ptr); - gl.Vertex2fv(center2.ptr); - }); -} - -void drawXForm(GL gl, bzXForm xf) -{ - bzVec2 p1 = xf.position, p2; - const k_axisScale = 0.4f; - - gl.Begin(GL_LINES); - { - gl.Color3f(1.0f, 0.0f, 0.0f); - gl.Vertex2f(p1.x, p1.y); - p2 = p1 + k_axisScale * xf.R.col1; - gl.Vertex2f(p2.x, p2.y); - - gl.Color3f(0.0f, 1.0f, 0.0f); - gl.Vertex2f(p1.x, p1.y); - p2 = p1 + k_axisScale * xf.R.col2; - gl.Vertex2f(p2.x, p2.y); - } - gl.End(); -} - -void drawSpring(GL gl, vec2 a, vec2 b, uint zigs) -{ - zigs++; - - // Portion of length dedicated to connectors - const float connPart = 0.2; - - vec2 inc = (b - a) / (zigs); - // One step from a to b - vec2 zigLen = inc * (1 - connPart); - // Length of a connector - vec2 connLen = inc * (connPart / 2) * zigs; - // Width of a zig - vec2 zigWidth = (b - a).rotatedHalfPi.normalized; - gl.immediate(GL_LINE_STRIP, - { - gl.Vertex2fv(a.ptr); - - a += connLen; - gl.Vertex2fv(a.ptr); - - bool dir = true; - a += zigWidth / 2 + zigLen / 2; - for (int i = 0; i < zigs; i++) { - gl.Vertex2fv(a.ptr); - a += zigLen; - if (dir) { - a -= zigWidth; - }else { - a += zigWidth; - } - dir = !dir; - } - - gl.Vertex2fv((b - connLen).ptr); - gl.Vertex2fv(b.ptr); - }); -} - -void drawShape(GL gl, bzShape shape, bzXForm xf, Color color, bool core) -{ - Color coreColor = Color(0.9f, 0.6f, 0.6f); - - switch (shape.type) { - case bzShapeType.CIRCLE: - auto circle = cast(bzCircle)shape; - - vec2 center = vec2.from(bzMul(xf, circle.localPosition)); - float radius = circle.radius; - vec2 axis = vec2.from(xf.R.col1); - - gl.drawSolidCircle(center, radius, axis, color); - - if (core) { - gl.Color3f(coreColor.r, coreColor.g, coreColor.b); - gl.drawCircle(center, radius - k_toiSlop); - } - break; - case bzShapeType.POLYGON: - { - bzPolygon poly = cast(bzPolygon)shape; - bzVec2[] vertices = poly.worldVertices; - vec2[] verts; - verts.length = vertices.length; - foreach (int i, v; vertices) { - verts[i] = vec2.from(v); - } - - gl.drawSolidPolygon(verts, color); - - if (core) { - bzVec2[] localCoreVertices = poly.coreVertices; - verts.length = localCoreVertices.length; - for (int i = 0; i < localCoreVertices.length; ++i) { - verts[i] = vec2.from(bzMul(xf, localCoreVertices[i])); - } - gl.drawPolygon(verts, coreColor); - } - } - break; - - case bzShapeType.EDGE: - { - bzEdge edge = cast(bzEdge)shape; - - vec2 p1 = vec2.from(bzMul(xf, edge.vertex1)); - vec2 p2 = vec2.from(bzMul(xf, edge.vertex2)); - gl.drawSegment(p1, p2, color); - - if (core) { - p1 = vec2.from(bzMul(xf, edge.coreVertex1)); - p2 = vec2.from(bzMul(xf, edge.coreVertex2)); - gl.drawSegment(p1, p2, coreColor); - } - } - break; - } -} - -void draw(vec2i screenSize, GL gl) -{ - - vec2 point1 = vec2.from(ship1.rBody.position); - vec2 point2 = vec2.from(ship2.rBody.position); - vec2 range = point1 - point2; - zoom = bzClamp(1000/range.length, 2, 60); - viewCenter = point1 - (range * 0.5f); - - this.screenSize = screenSize; - - gl.LoadIdentity(); - gl.MatrixMode(GL_PROJECTION); - gl.LoadIdentity(); - - float left = -screenSize.x / zoom; - float right = screenSize.x / zoom; - float bottom = -screenSize.y / zoom; - float top = screenSize.y / zoom; - - gl.gluOrtho2D(left, right, bottom, top); - gl.Translatef(-viewCenter.x, -viewCenter.y, 0); - gl.MatrixMode(GL_MODELVIEW); - gl.Disable(GL_DEPTH_TEST); - gl.LoadIdentity(); - gl.Clear(GL_COLOR_BUFFER_BIT); - - vec2 pp1 = vec2.from(ship2.rBody.position); - vec2 pp2 = vec2.from(ship2.state.target); - - //gl.drawSegment(pp1, pp2, Color(0, 1, 0)); - - // Draw dynamic bodies - if (settings.drawShapes) { - for (bzBody b = world.bodyList; b; b = b.next) { - for (bzShape shape = b.shapeList; shape; shape = shape.next) { - - bzShape s = shape; - bzXForm xf = b.xf; - - if (b.isStatic) { - gl.drawShape(s, xf, Color(0.5f, 0.9f, 0.5f), settings.drawCoreShapes); - }else if (b.isSleeping) { - gl.drawShape(s, xf, Color(0.5f, 0.5f, 0.9f), settings.drawCoreShapes); - }else if (b.userData) { - auto ss = cast(Select)b.userData; - if (ss) { - gl.drawShape(s, xf, Color(0, .5, 1), settings.drawCoreShapes); - } - }else { - gl.drawShape(s, xf, Color(0.9f, 0.9f, 0.9f), settings.drawCoreShapes); - } - - gl.LoadIdentity(); - gl.Flush(); - } - } - } - - // Draw joints - if (settings.drawJoints) { - Color color = Color(0, 0, 1); - gl.Color3f(0, 0, 1); - - gl.LineWidth(1); - for (bzJoint joint = world.jointList; joint; joint = joint.next) { - auto distance = cast(bzDistanceJoint)joint; - auto pulley = cast(bzPulleyJoint)joint; - auto revolute = cast(bzRevoluteJoint)joint; - auto prismatic = cast(bzPrismaticJoint)joint; - auto line = cast(bzLineJoint)joint; - if (distance) { - color = Color(.5, .5, 0); - // Endpoints - vec2 a = vec2.from(distance.anchor1); - vec2 b = vec2.from(distance.anchor2); - // Circles - gl.drawCircle(a, HINGE_RADIUS); - gl.drawCircle(b, HINGE_RADIUS); - // Connecting line - gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); - }else if (pulley) { - auto a = vec2.from(pulley.anchor1); - auto b = vec2.from(pulley.groundAnchor1); - auto c = vec2.from(pulley.groundAnchor2); - auto d = vec2.from(pulley.anchor2); - gl.drawCircle(a, HINGE_RADIUS); - gl.drawCircle(b, HINGE_RADIUS); - gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); - gl.drawSegment(b, c, color); - gl.drawCircle(c, HINGE_RADIUS); - gl.drawCircle(d, HINGE_RADIUS); - gl.connectCircles(c, HINGE_RADIUS, d, HINGE_RADIUS); - }else if (revolute) { - auto a = vec2.from(revolute.rBody1.position); - auto b = vec2.from(revolute.anchor1); - auto c = vec2.from(revolute.rBody2.position); - gl.drawCircle(a, HINGE_RADIUS); - gl.drawCircle(b, HINGE_RADIUS); - gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); - gl.drawCircle(c, HINGE_RADIUS); - gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS); - }else if (prismatic) { - auto a = vec2.from(prismatic.rBody1.position); - auto b = vec2.from(prismatic.anchor1); - auto c = vec2.from(prismatic.rBody2.position); - gl.drawCircle(a, HINGE_RADIUS); - gl.drawCircle(b, HINGE_RADIUS); - gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); - gl.drawCircle(c, HINGE_RADIUS); - gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS); - }else if (line) { - auto a = vec2.from(line.rBody1.position); - auto b = vec2.from(line.anchor1); - auto c = vec2.from(line.rBody2.position); - gl.drawCircle(a, HINGE_RADIUS); - gl.drawCircle(b, HINGE_RADIUS); - gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); - gl.drawCircle(c, HINGE_RADIUS); - gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS); - } - } - - if (settings.drawControllers) { - bzForceGenerator[] forces = world.forces; - foreach (f; forces) { - auto spring1 = cast(bzSpring1) f; - auto spring2 = cast(bzSpring2) f; - auto buoyancy = cast(bzBuoyancy) f; - - if (spring1) { - auto bungee1 = cast(bzBungee1)spring1; - if (bungee1) { - gl.Color3f(.5, .5, 0); - // Endpoints - vec2 a = vec2.from(bungee1.rBody.position); - vec2 b = vec2.from(bungee1.anchor); - // Circles - gl.drawCircle(a, HINGE_RADIUS); - gl.drawCircle(b, HINGE_RADIUS); - // Connecting line - gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); - }else { - uint zigs = 10; - auto anchor1 = vec2.from(spring1.anchor); - auto anchor2 = vec2.from(spring1.rBody.position); - gl.drawSpring(anchor1, anchor2, zigs); - } - } - - if (spring2) { - auto bungee2 = cast(bzBungee2)spring2; - if (bungee2) { - gl.Color3f(.5, .5, 0); - // Endpoints - vec2 a = vec2.from(bungee2.rBody.position); - vec2 b = vec2.from(bungee2.otherBody.position); - // Circles - gl.drawCircle(a, HINGE_RADIUS); - gl.drawCircle(b, HINGE_RADIUS); - // Connecting line - gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); - }else { - uint zigs = 10; - auto anchor1 = vec2.from(spring2.otherBody.position); - auto anchor2 = vec2.from(spring2.rBody.position); - gl.drawSpring(anchor1, anchor2, zigs); - } - } - - if(buoyancy) { - float plane = buoyancy.planeOffset; - vec2 p1 = vec2(-50, plane); - vec2 p2 = vec2(50, plane); - gl.drawSegment(p1, p2, color); - } - } - } - } - - if(settings.drawPairs) { - - bzBroadPhase bp = world.broadPhase; - bzVec2 invQ; - invQ.set(1.0f / bp.m_quantizationFactor.x, 1.0f / bp.m_quantizationFactor.y); - Color color = Color(0.9f, 0.9f, 0.3f); - - const k_tableCapacity = bzPairManager.TABLE_CAPACITY; - - for (int i = 0; i < k_tableCapacity; ++i) - { - ushort index = bp.m_pairManager.m_hashTable[i]; - while (index < bp.m_pairManager.m_pairs.length) - { - if(index == bzPairManager.NULL_PROXY) { - break; - } - bzPair pair = bp.m_pairManager.m_pairs[index]; - bzProxy p1 = bp.m_proxyPool[pair.proxyId1]; - bzProxy p2 = bp.m_proxyPool[pair.proxyId2]; - - bzAABB b1, b2; - b1.lowerBound.x = bp.m_worldAABB.lowerBound.x + invQ.x * bp.m_bounds[0][p1.lowerBounds[0]].value; - b1.lowerBound.y = bp.m_worldAABB.lowerBound.y + invQ.y * bp.m_bounds[1][p1.lowerBounds[1]].value; - b1.upperBound.x = bp.m_worldAABB.lowerBound.x + invQ.x * bp.m_bounds[0][p1.upperBounds[0]].value; - b1.upperBound.y = bp.m_worldAABB.lowerBound.y + invQ.y * bp.m_bounds[1][p1.upperBounds[1]].value; - b2.lowerBound.x = bp.m_worldAABB.lowerBound.x + invQ.x * bp.m_bounds[0][p2.lowerBounds[0]].value; - b2.lowerBound.y = bp.m_worldAABB.lowerBound.y + invQ.y * bp.m_bounds[1][p2.lowerBounds[1]].value; - b2.upperBound.x = bp.m_worldAABB.lowerBound.x + invQ.x * bp.m_bounds[0][p2.upperBounds[0]].value; - b2.upperBound.y = bp.m_worldAABB.lowerBound.y + invQ.y * bp.m_bounds[1][p2.upperBounds[1]].value; - - bzVec2 x1 = 0.5f * (b1.lowerBound + b1.upperBound); - bzVec2 x2 = 0.5f * (b2.lowerBound + b2.upperBound); - - gl.drawSegment(vec2.from(x1),vec2.from(x2), color); - - index = pair.next; - } - } - } - - // Draw the world bounds - bzBroadPhase bp = world.broadPhase; - bzVec2 worldLower = bp.m_worldAABB.lowerBound; - bzVec2 worldUpper = bp.m_worldAABB.upperBound; - Color color = Color(0.3f, 0.9f, 0.9f); - vec2 vs[4]; - vs[0] = vec2(worldLower.x, worldLower.y); - vs[1] = vec2(worldUpper.x, worldLower.y); - vs[2] = vec2(worldUpper.x, worldUpper.y); - vs[3] = vec2(worldLower.x, worldUpper.y); - drawPolygon(gl, vs, color); - - // Draw axis aligned bounding boxes (bzAABB) - if (settings.drawAABBs) { - bzVec2 invQ; - invQ.set(1.0f / bp.m_quantizationFactor.x, 1.0f / bp.m_quantizationFactor.y); - color = Color(1.0f, 1.0f, 1.0f); - - for (int i = 0; i < k_maxProxies; ++i) { - bzProxy p = bp.m_proxyPool[i]; - if (!p.isValid) { - continue; - } - - bzAABB b; - b.lowerBound.x = worldLower.x + invQ.x * bp.m_bounds[0][p.lowerBounds[0]].value; - b.lowerBound.y = worldLower.y + invQ.y * bp.m_bounds[1][p.lowerBounds[1]].value; - b.upperBound.x = worldLower.x + invQ.x * bp.m_bounds[0][p.upperBounds[0]].value; - b.upperBound.y = worldLower.y + invQ.y * bp.m_bounds[1][p.upperBounds[1]].value; - - vs[0] = vec2(b.lowerBound.x, b.lowerBound.y); - vs[1] = vec2(b.upperBound.x, b.lowerBound.y); - vs[2] = vec2(b.upperBound.x, b.upperBound.y); - vs[3] = vec2(b.lowerBound.x, b.upperBound.y); - - drawPolygon(gl, vs, color); - } - } -} - -} diff -r 82efafc87d54 -r 7f74e064dad5 render/render.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/render/render.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,571 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * Based on Box2D by Erin Catto, http://www.box2d.org + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.render.render; + +import tango.math.Math : PI; + +import xf.dog.Dog; +import xf.omg.core.LinearAlgebra; +import xf.hybrid.Event; +import xf.hybrid.Font; + +import blaze.bzWorld : bzWorld; +import blaze.dynamics.bzBody : bzBody; +import blaze.collision.shapes.bzShape : bzShape; +import blaze.collision.shapes.bzShapeType; +import blaze.collision.shapes.bzCircle : bzCircle; +import blaze.collision.shapes.bzPolygon : bzPolygon; +import blaze.collision.shapes.bzEdge : bzEdge; +import blaze.collision.nbody.bzBroadPhase : bzBroadPhase, bzProxy; +import blaze.collision.bzCollision : bzAABB; +import blaze.common.bzMath : bzXForm, bzVec2, bzMul, bzClamp; +import blaze.common.bzConstants : k_toiSlop,k_maxProxies; + +import openmelee.ships.ship : Ship; +import openmelee.melee.melee : Settings; + +// Cursor scale factor +const CURSORSIZE = 0.05f; +const INIT_SPAWN_SIZE = 0.5f; +// Dragging stuffs +const BUNGEE_K = 1.5f; +// Damping factor for dragging +const DRAGDAMP = 20.0f; +// Size of hinges +const HINGE_RADIUS = 0.05f; +// Smallest allowed dimension +const MIN_DIMENSION = 0.1; +const MAX_CIRCLE_RES = 32; + +/// Color for drawing. Each value has the range [0,1]. +struct Color { + static Color opCall(float r, float g, float b) + { + Color u; + u.r = r; + u.g = g; + u.b = b; + return u; + } + + float r = 0; + float g = 0; + float b = 0; +} + +class Render +{ + + float zoom = 40; + vec2 viewCenter; + bzWorld world; + vec2i screenSize; + bool scaling = false; + bool full = false; + Settings settings; + Ship ship1, ship2; + + this(bzWorld world, Ship s1, Ship s2, Settings settings) { + this.settings = settings; + ship1 = s1; + ship2 = s2; + this.world = world; + viewCenter = vec2(10, 10); + screenSize = vec2i.zero; + } + + void drawCircle(GL gl, vec2 center, float radius, bool water = false, float theta = float.nan) + { + int segs = cast(int)(radius) + 20; + if (segs > MAX_CIRCLE_RES) segs = MAX_CIRCLE_RES; + double coef = 2.0 * PI / segs; + + auto realTheta = (theta <>= 0 ? theta : 0); + if (water) { + gl.immediate(GL_TRIANGLE_FAN, + { + gl.Vertex2fv(center.ptr); + for (int n = 0; n <= segs; n++) { + double rads = n * coef; + gl.Vertex2f(radius * cos(rads + realTheta) + center.x, radius * sin(rads + realTheta) + center.y); + } + }); + } + + gl.immediate(GL_LINE_STRIP, + { + for (int n = 0; n <= segs; n++) { + double rads = n * coef; + gl.Vertex2f(radius * cos(rads + realTheta) + center.x, radius * sin(rads + realTheta) + center.y); + } + if (theta <>= 0) + gl.Vertex2fv(center.ptr); + }); + } + + void drawSolidCircle(GL gl, vec2 center, float radius, vec2 axis, Color color) + { + const k_segments = 25.0f; + const k_increment = 2.0f * PI / k_segments; + float theta = 0.0f; + gl.Enable(GL_BLEND); + gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl.Color4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f); + gl.Begin(GL_TRIANGLE_FAN); + for (int i = 0; i < k_segments; ++i) { + vec2 v = center + radius * vec2(cos(theta), sin(theta)); + gl.Vertex2f(v.x, v.y); + theta += k_increment; + } + gl.End(); + gl.Disable(GL_BLEND); + + theta = 0.0f; + gl.Color4f(color.r, color.g, color.b, 1.0f); + gl.Begin(GL_LINE_LOOP); + for (int i = 0; i < k_segments; ++i) { + vec2 v = center + radius * vec2(cos(theta), sin(theta)); + gl.Vertex2f(v.x, v.y); + theta += k_increment; + } + gl.End(); + + vec2 p = center + radius * axis; + gl.Begin(GL_LINES); + gl.Vertex2f(center.x, center.y); + gl.Vertex2f(p.x, p.y); + gl.End(); + } + + void drawPolygon(GL gl, vec2[] glVerts, Color color) + { + gl.Color3f(color.r, color.g, color.b); + gl.immediate(GL_LINE_LOOP, + { + foreach (v; glVerts) + gl.Vertex2fv(v.ptr); + }); + } + + void drawSolidPolygon(GL gl, vec2[] vertices, Color color) + { + gl.Enable(GL_BLEND); + gl.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl.Color4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f); + gl.Begin(GL_TRIANGLE_FAN); + for (int i = 0; i < vertices.length; ++i) { + gl.Vertex2f(vertices[i].x, vertices[i].y); + } + gl.End(); + gl.Disable(GL_BLEND); + + gl.Color4f(color.r, color.g, color.b, 1.0f); + gl.Begin(GL_LINE_LOOP); + for (int i = 0; i < vertices.length; ++i) { + gl.Vertex2f(vertices[i].x, vertices[i].y); + } + gl.End(); + } + + + void drawPoint(GL gl, vec2 p, float size, Color color) + { + gl.Color3f(color.r, color.g, color.b); + gl.PointSize(size); + gl.Begin(GL_POINTS); + gl.Vertex2f(p.x, p.y); + gl.End(); + gl.PointSize(1.0f); + } + + void drawSegment(GL gl, vec2 begin, vec2 end, Color color) + { + gl.Color3f(color.r, color.g, color.b); + gl.immediate(GL_LINES, + { + gl.Vertex2fv(begin.ptr); + gl.Vertex2fv(end.ptr); + }); + } + + // TODO: handle inequal radii correctly + void connectCircles(GL gl, vec2 center1, float radius1, vec2 center2, float radius2) + { + auto d = center2 - center1; + if (!d.length) + return; + d *= (d.length - radius1) / d.length; + center1 += d; + center2 -= d; + gl.immediate(GL_LINES, + { + gl.Vertex2fv(center1.ptr); + gl.Vertex2fv(center2.ptr); + }); + } + + void drawXForm(GL gl, bzXForm xf) + { + bzVec2 p1 = xf.position, p2; + const k_axisScale = 0.4f; + + gl.Begin(GL_LINES); + { + gl.Color3f(1.0f, 0.0f, 0.0f); + gl.Vertex2f(p1.x, p1.y); + p2 = p1 + k_axisScale * xf.R.col1; + gl.Vertex2f(p2.x, p2.y); + + gl.Color3f(0.0f, 1.0f, 0.0f); + gl.Vertex2f(p1.x, p1.y); + p2 = p1 + k_axisScale * xf.R.col2; + gl.Vertex2f(p2.x, p2.y); + } + gl.End(); + } + + void drawSpring(GL gl, vec2 a, vec2 b, uint zigs) + { + zigs++; + + // Portion of length dedicated to connectors + const float connPart = 0.2; + + vec2 inc = (b - a) / (zigs); + // One step from a to b + vec2 zigLen = inc * (1 - connPart); + // Length of a connector + vec2 connLen = inc * (connPart / 2) * zigs; + // Width of a zig + vec2 zigWidth = (b - a).rotatedHalfPi.normalized; + gl.immediate(GL_LINE_STRIP, + { + gl.Vertex2fv(a.ptr); + + a += connLen; + gl.Vertex2fv(a.ptr); + + bool dir = true; + a += zigWidth / 2 + zigLen / 2; + for (int i = 0; i < zigs; i++) { + gl.Vertex2fv(a.ptr); + a += zigLen; + if (dir) { + a -= zigWidth; + }else { + a += zigWidth; + } + dir = !dir; + } + + gl.Vertex2fv((b - connLen).ptr); + gl.Vertex2fv(b.ptr); + }); + } + + void drawShape(GL gl, bzShape shape, bzXForm xf, Color color, bool core) + { + Color coreColor = Color(0.9f, 0.6f, 0.6f); + + switch (shape.type) { + case bzShapeType.CIRCLE: + auto circle = cast(bzCircle)shape; + + vec2 center = vec2.from(bzMul(xf, circle.localPosition)); + float radius = circle.radius; + vec2 axis = vec2.from(xf.R.col1); + + gl.drawSolidCircle(center, radius, axis, color); + + if (core) { + gl.Color3f(coreColor.r, coreColor.g, coreColor.b); + gl.drawCircle(center, radius - k_toiSlop); + } + break; + case bzShapeType.POLYGON: + { + bzPolygon poly = cast(bzPolygon)shape; + bzVec2[] vertices = poly.worldVertices; + vec2[] verts; + verts.length = vertices.length; + foreach (int i, v; vertices) { + verts[i] = vec2.from(v); + } + + gl.drawSolidPolygon(verts, color); + + if (core) { + bzVec2[] localCoreVertices = poly.coreVertices; + verts.length = localCoreVertices.length; + for (int i = 0; i < localCoreVertices.length; ++i) { + verts[i] = vec2.from(bzMul(xf, localCoreVertices[i])); + } + gl.drawPolygon(verts, coreColor); + } + } + break; + + case bzShapeType.EDGE: + { + bzEdge edge = cast(bzEdge)shape; + + vec2 p1 = vec2.from(bzMul(xf, edge.vertex1)); + vec2 p2 = vec2.from(bzMul(xf, edge.vertex2)); + gl.drawSegment(p1, p2, color); + + if (core) { + p1 = vec2.from(bzMul(xf, edge.coreVertex1)); + p2 = vec2.from(bzMul(xf, edge.coreVertex2)); + gl.drawSegment(p1, p2, coreColor); + } + } + break; + } + } + + void draw(vec2i screenSize, GL gl) + { + + vec2 point1 = vec2.from(ship1.rBody.position); + vec2 point2 = vec2.from(ship2.rBody.position); + vec2 range = point1 - point2; + zoom = bzClamp(1000/range.length, 2, 60); + viewCenter = point1 - (range * 0.5f); + + this.screenSize = screenSize; + + gl.LoadIdentity(); + gl.MatrixMode(GL_PROJECTION); + gl.LoadIdentity(); + + float left = -screenSize.x / zoom; + float right = screenSize.x / zoom; + float bottom = -screenSize.y / zoom; + float top = screenSize.y / zoom; + + gl.gluOrtho2D(left, right, bottom, top); + gl.Translatef(-viewCenter.x, -viewCenter.y, 0); + gl.MatrixMode(GL_MODELVIEW); + gl.Disable(GL_DEPTH_TEST); + gl.LoadIdentity(); + gl.Clear(GL_COLOR_BUFFER_BIT); + + vec2 pp1 = vec2.from(ship2.rBody.position); + vec2 pp2 = vec2.from(ship2.state.target); + + //gl.drawSegment(pp1, pp2, Color(0, 1, 0)); + + // Draw dynamic bodies + if (settings.drawShapes) { + for (bzBody b = world.bodyList; b; b = b.next) { + for (bzShape shape = b.shapeList; shape; shape = shape.next) { + + bzShape s = shape; + bzXForm xf = b.xf; + + if (b.isStatic) { + gl.drawShape(s, xf, Color(0.5f, 0.9f, 0.5f), settings.drawCoreShapes); + }else if (b.isSleeping) { + gl.drawShape(s, xf, Color(0.5f, 0.5f, 0.9f), settings.drawCoreShapes); + }else { + gl.drawShape(s, xf, Color(0.9f, 0.9f, 0.9f), settings.drawCoreShapes); + } + + gl.LoadIdentity(); + gl.Flush(); + } + } + } + + // Draw joints + /* + if (settings.drawJoints) { + Color color = Color(0, 0, 1); + gl.Color3f(0, 0, 1); + + gl.LineWidth(1); + for (bzJoint joint = world.jointList; joint; joint = joint.next) { + auto distance = cast(bzDistanceJoint)joint; + auto pulley = cast(bzPulleyJoint)joint; + auto revolute = cast(bzRevoluteJoint)joint; + auto prismatic = cast(bzPrismaticJoint)joint; + auto line = cast(bzLineJoint)joint; + if (distance) { + color = Color(.5, .5, 0); + // Endpoints + vec2 a = vec2.from(distance.anchor1); + vec2 b = vec2.from(distance.anchor2); + // Circles + gl.drawCircle(a, HINGE_RADIUS); + gl.drawCircle(b, HINGE_RADIUS); + // Connecting line + gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); + }else if (pulley) { + auto a = vec2.from(pulley.anchor1); + auto b = vec2.from(pulley.groundAnchor1); + auto c = vec2.from(pulley.groundAnchor2); + auto d = vec2.from(pulley.anchor2); + gl.drawCircle(a, HINGE_RADIUS); + gl.drawCircle(b, HINGE_RADIUS); + gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); + gl.drawSegment(b, c, color); + gl.drawCircle(c, HINGE_RADIUS); + gl.drawCircle(d, HINGE_RADIUS); + gl.connectCircles(c, HINGE_RADIUS, d, HINGE_RADIUS); + }else if (revolute) { + auto a = vec2.from(revolute.rBody1.position); + auto b = vec2.from(revolute.anchor1); + auto c = vec2.from(revolute.rBody2.position); + gl.drawCircle(a, HINGE_RADIUS); + gl.drawCircle(b, HINGE_RADIUS); + gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); + gl.drawCircle(c, HINGE_RADIUS); + gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS); + }else if (prismatic) { + auto a = vec2.from(prismatic.rBody1.position); + auto b = vec2.from(prismatic.anchor1); + auto c = vec2.from(prismatic.rBody2.position); + gl.drawCircle(a, HINGE_RADIUS); + gl.drawCircle(b, HINGE_RADIUS); + gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); + gl.drawCircle(c, HINGE_RADIUS); + gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS); + }else if (line) { + auto a = vec2.from(line.rBody1.position); + auto b = vec2.from(line.anchor1); + auto c = vec2.from(line.rBody2.position); + gl.drawCircle(a, HINGE_RADIUS); + gl.drawCircle(b, HINGE_RADIUS); + gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); + gl.drawCircle(c, HINGE_RADIUS); + gl.connectCircles(b, HINGE_RADIUS, c, HINGE_RADIUS); + } + } + + + if (settings.drawControllers) { + bzForceGenerator[] forces = world.forces; + foreach (f; forces) { + auto spring1 = cast(bzSpring1) f; + auto spring2 = cast(bzSpring2) f; + auto buoyancy = cast(bzBuoyancy) f; + + if (spring1) { + auto bungee1 = cast(bzBungee1)spring1; + if (bungee1) { + gl.Color3f(.5, .5, 0); + // Endpoints + vec2 a = vec2.from(bungee1.rBody.position); + vec2 b = vec2.from(bungee1.anchor); + // Circles + gl.drawCircle(a, HINGE_RADIUS); + gl.drawCircle(b, HINGE_RADIUS); + // Connecting line + gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); + }else { + uint zigs = 10; + auto anchor1 = vec2.from(spring1.anchor); + auto anchor2 = vec2.from(spring1.rBody.position); + gl.drawSpring(anchor1, anchor2, zigs); + } + } + + if (spring2) { + auto bungee2 = cast(bzBungee2)spring2; + if (bungee2) { + gl.Color3f(.5, .5, 0); + // Endpoints + vec2 a = vec2.from(bungee2.rBody.position); + vec2 b = vec2.from(bungee2.otherBody.position); + // Circles + gl.drawCircle(a, HINGE_RADIUS); + gl.drawCircle(b, HINGE_RADIUS); + // Connecting line + gl.connectCircles(a, HINGE_RADIUS, b, HINGE_RADIUS); + }else { + uint zigs = 10; + auto anchor1 = vec2.from(spring2.otherBody.position); + auto anchor2 = vec2.from(spring2.rBody.position); + gl.drawSpring(anchor1, anchor2, zigs); + } + } + + if(buoyancy) { + float plane = buoyancy.planeOffset; + vec2 p1 = vec2(-50, plane); + vec2 p2 = vec2(50, plane); + gl.drawSegment(p1, p2, color); + } + } + } + } + */ + + // Draw the world bounds + bzBroadPhase bp = world.broadPhase; + bzVec2 worldLower = bp.m_worldAABB.lowerBound; + bzVec2 worldUpper = bp.m_worldAABB.upperBound; + Color color = Color(0.3f, 0.9f, 0.9f); + vec2 vs[4]; + vs[0] = vec2(worldLower.x, worldLower.y); + vs[1] = vec2(worldUpper.x, worldLower.y); + vs[2] = vec2(worldUpper.x, worldUpper.y); + vs[3] = vec2(worldLower.x, worldUpper.y); + drawPolygon(gl, vs, color); + + // Draw axis aligned bounding boxes (bzAABB) + if (settings.drawAABBs) { + bzVec2 invQ; + invQ.set(1.0f / bp.m_quantizationFactor.x, 1.0f / bp.m_quantizationFactor.y); + color = Color(1.0f, 1.0f, 1.0f); + + for (int i = 0; i < k_maxProxies; ++i) { + bzProxy p = bp.m_proxyPool[i]; + if (!p.isValid) { + continue; + } + + bzAABB b; + b.lowerBound.x = worldLower.x + invQ.x * bp.m_bounds[0][p.lowerBounds[0]].value; + b.lowerBound.y = worldLower.y + invQ.y * bp.m_bounds[1][p.lowerBounds[1]].value; + b.upperBound.x = worldLower.x + invQ.x * bp.m_bounds[0][p.upperBounds[0]].value; + b.upperBound.y = worldLower.y + invQ.y * bp.m_bounds[1][p.upperBounds[1]].value; + + vs[0] = vec2(b.lowerBound.x, b.lowerBound.y); + vs[1] = vec2(b.upperBound.x, b.lowerBound.y); + vs[2] = vec2(b.upperBound.x, b.upperBound.y); + vs[3] = vec2(b.lowerBound.x, b.upperBound.y); + + drawPolygon(gl, vs, color); + } + } + } +} diff -r 82efafc87d54 -r 7f74e064dad5 ship.d --- a/ship.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2009, Mason Green (zzzzrrr) - * http://www.dsource.org/projects/openmelee - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the polygonal nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -module openmelee.ship; - -import tango.io.Stdout: Stdout; - -import tango.util.container.LinkedList : LinkedList; -import blaze.dynamics.bzBody : bzBody; -import blaze.collision.shapes.bzShape : bzShape; -import blaze.common.bzMath: bzVec2, bzCross, bzClamp; -import blaze.bzWorld : bzWorld; -import blaze.dynamics.forces.bzAttractor: bzAttractor; - -alias LinkedList!(bzShape) ShapeList; - -struct State -{ - bzVec2 position; - bzVec2 velocity; - bzVec2 up; - bzVec2 side; - bzVec2 forward; - bzVec2 target; - float speed = 0; - float maxForce = 0; - bool turn; - - float enemyAngle; - - bzVec2 predictFuturePosition(float dt) { - return (position + velocity * dt); - } -} - -abstract class Ship -{ - bzWorld world; - bzBody rBody; - ShapeList shapes; - bzVec2 engineForce; - bzVec2 turnForce; - bzVec2 leftTurnPoint; - bzVec2 rightTurnPoint; - State state; - - float battery; - float crew; - - float maxLinVel = 50; - float maxAngVel = 2; - - this(bzWorld world) { - - this.world = world; - shapes = new ShapeList; - } - - void thrust() { - rBody.force += engineForce.rotate(rBody.angle); - } - - void turnLeft() { - - rBody.torque += bzCross(leftTurnPoint.rotate(rBody.angle), - turnForce.rotate(rBody.angle)); - } - - void turnRight() { - - rBody.torque += bzCross(rightTurnPoint.rotate(rBody.angle), - turnForce.rotate(rBody.angle)); - } - - void setPlanetGravity() { - float minRadius = 0.1; - float maxRadius = 10; - float strength = 4.0; - bzVec2 center = bzVec2(0,0); - auto attractor = new bzAttractor(rBody, center, strength, minRadius, maxRadius); - world.addForce(attractor); - } - - void limitVelocity() { - float vx = rBody.linearVelocity.x; - float vy = rBody.linearVelocity.y; - float av = rBody.angularVelocity; - rBody.linearVelocity.x = bzClamp(vx, -maxLinVel, maxLinVel); - rBody.linearVelocity.y = bzClamp(vy, -maxLinVel, maxLinVel); - rBody.angularVelocity = bzClamp(av, -maxAngVel, maxAngVel); - } - - void updateState() { - state.velocity = rBody.linearVelocity; - state.speed = state.velocity.length; - state.position = rBody.position; - state.forward = engineForce.rotate(rBody.angle); - } - -} diff -r 82efafc87d54 -r 7f74e064dad5 ships/models.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ships/models.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,239 @@ +void spathiEluder(inout bzVec2[][] bodyVertex, inout bzVec2[][] vertex) +{ + vertex.length = bodyVertex.length = 11; + + vertex[0].length = bodyVertex[0].length = 19; + // Hull + bodyVertex[0][0] = bzVec2(2.24,31.54); + bodyVertex[0][1] = bzVec2(14.14,28.28); + bodyVertex[0][2] = bzVec2(23.89,20.72); + bodyVertex[0][3] = bzVec2(30.00,10.00); + bodyVertex[0][4] = bzVec2(31.54, -2.24); + bodyVertex[0][5] = bzVec2(28.28,-14.14); + bodyVertex[0][6] = bzVec2(22.48,-21.62); + bodyVertex[0][7] = bzVec2(20.72,-23.89); + bodyVertex[0][8] = bzVec2(10.00,-30.00); + bodyVertex[0][9] = bzVec2(-2.24,-31.54); + bodyVertex[0][10] = bzVec2(-8.19,-29.91); + bodyVertex[0][11] = bzVec2(-19.02,-24.50); + bodyVertex[0][12] = bzVec2(-23.89,-20.72); + bodyVertex[0][13] = bzVec2(-30.00,-10.00); + bodyVertex[0][14] = bzVec2(-31.00,-5.00); + bodyVertex[0][15] = bzVec2(-31.00,5.00); + bodyVertex[0][16] = bzVec2(-28.28,14.14); + bodyVertex[0][17] = bzVec2(-20.72,23.89); + bodyVertex[0][18] = bzVec2(-10.00,30.00); + + vertex[1].length = bodyVertex[1].length = 4; + // Body + bodyVertex[1][0] = bzVec2(14.14,28.28); + bodyVertex[1][1] = bzVec2(23.89,20.72); + bodyVertex[1][2] = bzVec2(44.56,47.70); + bodyVertex[1][3] = bzVec2(35.97,54.29); + + vertex[2].length = bodyVertex[2].length = 4; + // Top Strut + bodyVertex[2][0] = bzVec2(22.48,-21.62); + bodyVertex[2][1] = bzVec2(28.28,-14.14); + bodyVertex[2][2] = bzVec2(53.41,-29.39); + bodyVertex[2][3] = bzVec2(46.67,-37.86); + + vertex[3].length = bodyVertex[3].length = 4; + // Top Wing + bodyVertex[3][0] = bzVec2(-19.02,-24.50); + bodyVertex[3][1] = bzVec2(-8.19,-29.91); + bodyVertex[3][2] = bzVec2(-36.26,-62.25); + bodyVertex[3][3] = bzVec2(-42.85,-53.66); + + vertex[4].length = bodyVertex[4].length = 4; + // Bottom Strut + bodyVertex[4][0] = bzVec2(-31.00,-5.00); + bodyVertex[4][1] = bzVec2(-31.00,5.00); + bodyVertex[4][2] = bzVec2(-46.00,5.00); + bodyVertex[4][3] = bzVec2(-46.00,-5.00); + + vertex[5].length = bodyVertex[5].length = 4; + // Bottom Wing + bodyVertex[5][0] = bzVec2(-10.00,30.00); + bodyVertex[5][1] = bzVec2(-20.72,23.89); + bodyVertex[5][2] = bzVec2(-50.00,65.86); + bodyVertex[5][3] = bzVec2(-40.00,70.00); + + vertex[6].length = bodyVertex[6].length = 8; + // Rear, top Pod + bodyVertex[6][0] = bzVec2(-40.00 ,70.00); + bodyVertex[6][1] = bzVec2(-35.86 , 80.00); + bodyVertex[6][2] = bzVec2( -40.00, 90.00); + bodyVertex[6][3] = bzVec2( -50.00,94.14); + bodyVertex[6][4] = bzVec2( -60.00, 90.00); + bodyVertex[6][5] = bzVec2(-64.14 , 80.00); + bodyVertex[6][6] = bzVec2(-60.00 , 70.00); + bodyVertex[6][7] = bzVec2(-50.00 ,65.86); + + vertex[7].length = bodyVertex[7].length = 8; + // Rear, middle pod + bodyVertex[7][0] = bzVec2(-46.00,5.00); + bodyVertex[7][1] = bzVec2( -46.00,-5.00); + bodyVertex[7][2] = bzVec2(-54.47 ,-12.02); + bodyVertex[7][3] = bzVec2( -65.30, -13.11); + bodyVertex[7][4] = bzVec2( -73.02, -5.53); + bodyVertex[7][5] = bzVec2( -73.11,5.30); + bodyVertex[7][6] = bzVec2( -65.53, 13.02); + bodyVertex[7][7] = bzVec2( -54.70,13.11); + + + vertex[8].length = bodyVertex[8].length = 8; + // Rear, bottom pod + bodyVertex[8][0] = bzVec2( -36.26,-62.25); + bodyVertex[8][1] = bzVec2( -42.85,-53.66); + bodyVertex[8][2] = bzVec2( -53.59,-52.25); + bodyVertex[8][3] = bzVec2( -62.17,-58.84); + bodyVertex[8][4] = bzVec2( -63.59,-69.57); + bodyVertex[8][5] = bzVec2( -57.00,-78.16); + bodyVertex[8][6] = bzVec2( -46.26,-79.57); + bodyVertex[8][7] = bzVec2( -37.68,-72.98); + + vertex[9].length = bodyVertex[9].length = 8; + + bodyVertex[9][0] = bzVec2( 53.41, -29.39); + bodyVertex[9][1] = bzVec2( 46.67,-37.86); + bodyVertex[9][2] = bzVec2( 47.89,-47.61); + bodyVertex[9][3] = bzVec2( 56.36, -55.35); + bodyVertex[9][4] = bzVec2( 67.12,-54.12); + bodyVertex[9][5] = bzVec2( 73.86, -45.65); + bodyVertex[9][6] = bzVec2( 72.63,-34.90); + bodyVertex[9][7] = bzVec2( 64.16,-28.16); + + vertex[10].length = bodyVertex[10].length = 8; + + bodyVertex[10][0] = bzVec2( 35.97, 54.29); + bodyVertex[10][1] = bzVec2( 44.56, 47.70); + bodyVertex[10][2] = bzVec2( 56.29, 49.12 ); + bodyVertex[10][3] = bzVec2( 61.88, 57.70); + bodyVertex[10][4] = bzVec2( 60.47, 68.44); + bodyVertex[10][5] = bzVec2( 51.88, 75.02); + bodyVertex[10][6] = bzVec2( 41.15, 73.61); + bodyVertex[10][7] = bzVec2( 34.56, 65.02); +} + +void urQuanDreadnought(inout bzVec2[][] bodyVertex, inout bzVec2[][] vertex) +{ + vertex.length = bodyVertex.length = 6; + + vertex[0].length = bodyVertex[0].length = 8; + // Head + bodyVertex[0][0] = bzVec2(42,49); + bodyVertex[0][1] = bzVec2(63,49); + bodyVertex[0][2] = bzVec2(70,45.5); + bodyVertex[0][3] = bzVec2(73.5,38.5); + bodyVertex[0][4] = bzVec2(73.5,-42); + bodyVertex[0][5] = bzVec2(70,-49); + bodyVertex[0][6] = bzVec2(63,-56); + bodyVertex[0][7] = bzVec2(42,-56); + + vertex[1].length = bodyVertex[1].length = 4; + // Body + bodyVertex[1][0] = bzVec2(-70,-28); + bodyVertex[1][1] = bzVec2(-70,24.5); + bodyVertex[1][2] = bzVec2(42,24.5); + bodyVertex[1][3] = bzVec2(42,-31.5); + + vertex[2].length = bodyVertex[2].length = 4; + // Top Strut + bodyVertex[2][0] = bzVec2(0,24.5); + bodyVertex[2][1] = bzVec2(-28,24.5); + bodyVertex[2][2] = bzVec2(-28,42); + bodyVertex[2][3] = bzVec2(0,42); + + vertex[3].length = bodyVertex[3].length = 4; + // Top Wing + bodyVertex[3][0] = bzVec2(-70,42); + bodyVertex[3][1] = bzVec2(-49,63); + bodyVertex[3][2] = bzVec2(28,63); + bodyVertex[3][3] = bzVec2(28,42); + + vertex[4].length = bodyVertex[4].length = 4; + // Bottom Strut + bodyVertex[4][0] = bzVec2(0,-31.5); + bodyVertex[4][1] = bzVec2(0,-49); + bodyVertex[4][2] = bzVec2(-28,-49); + bodyVertex[4][3] = bzVec2(-28,-31.5); + + vertex[5].length = bodyVertex[5].length = 4; + // Bottom Wing + bodyVertex[5][0] = bzVec2(-70,-49); + bodyVertex[5][1] = bzVec2(28,-49); + bodyVertex[5][2] = bzVec2(28,-70); + bodyVertex[5][3] = bzVec2(-42,-70); +} + +void yehatTerminator(inout bzVec2[][] bodyVertex, inout bzVec2[][] vertex) +{ + vertex.length = bodyVertex.length = 4; + vertex[0].length = bodyVertex[0].length = 3; + // Cockpit + bodyVertex[0][0] = bzVec2(-14,21); + bodyVertex[0][1] = bzVec2(0,42); + bodyVertex[0][2] = bzVec2(14,21); + + + vertex[1].length = bodyVertex[1].length = 4; + // Body + bodyVertex[1][0] = bzVec2(-14,21); + bodyVertex[1][1] = bzVec2(-14,-21); + bodyVertex[1][2] = bzVec2(14,-21); + bodyVertex[1][3] = bzVec2(14,21); + + vertex[2].length = bodyVertex[2].length = 4; + // Right Wing + bodyVertex[2][0] = bzVec2(14,21); + bodyVertex[2][1] = bzVec2(14,-21); + bodyVertex[2][2] = bzVec2(70,0); + bodyVertex[2][3] = bzVec2(84,59.5); + + vertex[3].length = bodyVertex[3].length = 4; + // Left Wing + bodyVertex[3][0] = bzVec2(-14,21); + bodyVertex[3][1] = bzVec2(-14,-21); + bodyVertex[3][2] = bzVec2(-70,0); + bodyVertex[3][3] = bzVec2(-84,59.5); +} + +void orzNemesis(inout bzVec2[][] bodyVertex, inout bzVec2[][] vertex) +{ + vertex.length = bodyVertex.length = 3; + vertex[0].length = bodyVertex[0].length = 4; + // Body + bodyVertex[0][0] = bzVec2(-28,21); + bodyVertex[0][1] = bzVec2(-28,-28); + bodyVertex[0][2] = bzVec2(42,-21); + bodyVertex[0][3] = bzVec2(42,14); + + vertex[1].length = bodyVertex[1].length = 5; + // Top Wing + bodyVertex[1][0] = bzVec2(-28,21); + bodyVertex[1][1] = bzVec2(-70,63); + bodyVertex[1][2] = bzVec2(-49,63); + bodyVertex[1][3] = bzVec2(70,14); + bodyVertex[1][4] = bzVec2(42,14); + + vertex[2].length = bodyVertex[2].length = 5; + // Bottom Wing + bodyVertex[2][0] = bzVec2(-28,-28); + bodyVertex[2][1] = bzVec2(-70,-63); + bodyVertex[2][2] = bzVec2(-49,-63); + bodyVertex[2][3] = bzVec2(70,-21); + bodyVertex[2][4] = bzVec2(42,-21); +} + +void triangle(inout bzVec2[][] bodyVertex, inout bzVec2[][] vertex) +{ + + vertex.length = bodyVertex.length = 1; + vertex[0].length = bodyVertex[0].length = 3; + + bodyVertex[0][0] = bzVec2(0.0f,7.0f); + bodyVertex[0][1] = bzVec2(7.0f,-7.0f); + bodyVertex[0][2] = bzVec2(-7.0f,-7.0f); + +} diff -r 82efafc87d54 -r 7f74e064dad5 ships/orz.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ships/orz.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * http://www.dsource.org/projects/openmelee + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.ships.orz; + +import blaze.dynamics.bzBody : bzBody; +import blaze.bzWorld: bzWorld; +import blaze.dynamics.bzBodyDef; +import blaze.collision.shapes.bzPolygon : bzPolyDef; +import blaze.common.bzMath: bzVec2, PI; + +import openmelee.ships.ship; + +// UrQuan Dreadnought +class Orz : Ship +{ + + float scale = 0.025; + + this(bzWorld world) { + + super(world); + engineForce = bzVec2(500, 0); + turnForce = bzVec2(0, 5000); + rightTurnPoint = bzVec2(-0.5, 0); + leftTurnPoint = bzVec2(0.5, 0); + + auto bodyDef = new bzBodyDef; + //bodyDef.isBullet = true; + bodyDef.position = bzVec2(20,15); + bodyDef.angle = PI/2; + bodyDef.allowFreeze = false; + + rBody = world.createBody(bodyDef); + float density = 5.0f; + + // Body + auto b = new bzPolyDef(density); + b.vertices.length = 4; + b.vertices[0] = bzVec2(42,14) * scale; + b.vertices[1] = bzVec2(-28,21) * scale; + b.vertices[2] = bzVec2(-28,-28) * scale; + b.vertices[3] = bzVec2(42,-21) * scale; + shapes.add(rBody.createShape(b)); + + // Top Wing + auto tWing = new bzPolyDef(density); + tWing.vertices.length = 5; + tWing.vertices[4] = bzVec2(-28,21) * scale; + tWing.vertices[3] = bzVec2(-70,63) * scale; + tWing.vertices[2] = bzVec2(-49,63) * scale; + tWing.vertices[1] = bzVec2(70,14) * scale; + tWing.vertices[0] = bzVec2(42,14) * scale; + shapes.add(rBody.createShape(tWing)); + + // Bottom Wing + auto bWing = new bzPolyDef(density); + bWing.vertices.length = 5; + bWing.vertices[0] = bzVec2(-28,-28) * scale; + bWing.vertices[1] = bzVec2(-70,-63) * scale; + bWing.vertices[2] = bzVec2(-49,-63) * scale; + bWing.vertices[3] = bzVec2(70,-21) * scale; + bWing.vertices[4] = bzVec2(42,-21) * scale; + shapes.add(rBody.createShape(bWing)); + + rBody.setMassFromShapes(); + setPlanetGravity(); + } +} diff -r 82efafc87d54 -r 7f74e064dad5 ships/planet.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ships/planet.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * http://www.dsource.org/projects/openmelee + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.ships.planet; + +import blaze.dynamics.bzBody : bzBody; +import blaze.bzWorld: bzWorld; +import blaze.dynamics.bzBodyDef; +import blaze.collision.shapes.bzCircle : bzCircleDef; +import blaze.common.bzMath: bzVec2; + +class Planet +{ + + bzWorld world; + + this(bzWorld world) { + this.world = world; + init(); + } + + void init() { + // Create planet + bzVec2 position = bzVec2.zeroVect; + float angle = 0.0f; + auto bd = new bzBodyDef(position, angle); + auto rBody = world.createBody(bd); + float radius = 7.0f; + float density = 7.5f; + auto sd = new bzCircleDef(density, radius); + float friction = 1.0f; + float restitution = 0.1f; + sd.friction = friction; + sd.restitution = restitution; + rBody.createShape(sd); + } +} diff -r 82efafc87d54 -r 7f74e064dad5 ships/ship.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ships/ship.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * http://www.dsource.org/projects/openmelee + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.ships.ship; + +import tango.io.Stdout: Stdout; + +import tango.util.container.LinkedList : LinkedList; +import blaze.dynamics.bzBody : bzBody; +import blaze.collision.shapes.bzShape : bzShape; +import blaze.common.bzMath: bzVec2, bzCross, bzClamp; +import blaze.bzWorld : bzWorld; +import blaze.dynamics.forces.bzAttractor: bzAttractor; + +alias LinkedList!(bzShape) ShapeList; + +struct State +{ + bzVec2 position; + bzVec2 velocity; + bzVec2 up; + bzVec2 side; + bzVec2 forward; + bzVec2 target; + float speed = 0; + float maxForce = 0; + bool turn; + + float enemyAngle; + + bzVec2 predictFuturePosition(float dt) { + return (position + velocity * dt); + } +} + +abstract class Ship +{ + bzWorld world; + bzBody rBody; + ShapeList shapes; + bzVec2 engineForce; + bzVec2 turnForce; + bzVec2 leftTurnPoint; + bzVec2 rightTurnPoint; + State state; + + float battery; + float crew; + + float maxLinVel = 50; + float maxAngVel = 2; + + this(bzWorld world) { + + this.world = world; + shapes = new ShapeList; + } + + void thrust() { + rBody.force += engineForce.rotate(rBody.angle); + } + + void turnLeft() { + + rBody.torque += bzCross(leftTurnPoint.rotate(rBody.angle), + turnForce.rotate(rBody.angle)); + } + + void turnRight() { + + rBody.torque += bzCross(rightTurnPoint.rotate(rBody.angle), + turnForce.rotate(rBody.angle)); + } + + void setPlanetGravity() { + float minRadius = 0.1; + float maxRadius = 10; + float strength = 4.0; + bzVec2 center = bzVec2(0,0); + auto attractor = new bzAttractor(rBody, center, strength, minRadius, maxRadius); + world.addForce(attractor); + } + + void limitVelocity() { + float vx = rBody.linearVelocity.x; + float vy = rBody.linearVelocity.y; + float av = rBody.angularVelocity; + rBody.linearVelocity.x = bzClamp(vx, -maxLinVel, maxLinVel); + rBody.linearVelocity.y = bzClamp(vy, -maxLinVel, maxLinVel); + rBody.angularVelocity = bzClamp(av, -maxAngVel, maxAngVel); + } + + void updateState() { + state.velocity = rBody.linearVelocity; + state.speed = state.velocity.length; + state.position = rBody.position; + state.forward = engineForce.rotate(rBody.angle); + } + +} diff -r 82efafc87d54 -r 7f74e064dad5 ships/urQuan.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ships/urQuan.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2009, Mason Green (zzzzrrr) + * http://www.dsource.org/projects/openmelee + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the polygonal nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +module openmelee.ships.urQuan; + +import blaze.dynamics.bzBody : bzBody; +import blaze.bzWorld: bzWorld; +import blaze.dynamics.bzBodyDef; +import blaze.collision.shapes.bzPolygon : bzPolyDef; +import blaze.common.bzMath: bzVec2; + +import openmelee.ships.ship; + +// UrQuan Dreadnought +class UrQuan : Ship +{ + + float scale = 0.025; + + this(bzWorld world) { + + super(world); + engineForce = bzVec2(500, 0); + turnForce = bzVec2(0, 9000); + rightTurnPoint = bzVec2(-0.5, 0); + leftTurnPoint = bzVec2(0.5, 0); + + auto bodyDef = new bzBodyDef; + //bodyDef.isBullet = true; + bodyDef.position = bzVec2(30,5); + bodyDef.allowFreeze = false; + rBody = world.createBody(bodyDef); + float density = 5.0f; + + // Head + auto head = new bzPolyDef; + head.vertices.length = 8; + head.vertices[0] = bzVec2(42,49) * scale; + head.vertices[7] = bzVec2(63,49) * scale; + head.vertices[6] = bzVec2(70,45.5) * scale; + head.vertices[5] = bzVec2(73.5,38.5) * scale; + head.vertices[4] = bzVec2(73.5,-42) * scale; + head.vertices[3] = bzVec2(70,-49) * scale; + head.vertices[2] = bzVec2(63,-56) * scale; + head.vertices[1] = bzVec2(42,-56) * scale; + shapes.add(rBody.createShape(head)); + + // Body + auto b = new bzPolyDef(density); + b.vertices.length = 4; + b.vertices[0] = bzVec2(-70,-28) * scale; + b.vertices[3] = bzVec2(-70,24.5) * scale; + b.vertices[2] = bzVec2(42,24.5) * scale; + b.vertices[1] = bzVec2(42,-31.5) * scale; + shapes.add(rBody.createShape(b)); + + // Top Strut + auto tStrut = new bzPolyDef(density); + tStrut.vertices.length = 4; + tStrut.vertices[0] = bzVec2(0,24.5) * scale; + tStrut.vertices[3] = bzVec2(-28,24.5) * scale; + tStrut.vertices[2] = bzVec2(-28,42) * scale; + tStrut.vertices[1] = bzVec2(0,42) * scale; + shapes.add(rBody.createShape(tStrut)); + + // Top Wing + auto tWing = new bzPolyDef(density); + tWing.vertices.length = 4; + tWing.vertices[0] = bzVec2(-70,42) * scale; + tWing.vertices[3] = bzVec2(-49,63) * scale; + tWing.vertices[2] = bzVec2(28,63) * scale; + tWing.vertices[1] = bzVec2(28,42) * scale; + shapes.add(rBody.createShape(tWing)); + + // Bottom Strut + auto bStrut = new bzPolyDef(density); + bStrut.vertices.length = 4; + bStrut.vertices[0] = bzVec2(0,-31.5) * scale; + bStrut.vertices[3] = bzVec2(0,-49) * scale; + bStrut.vertices[2] = bzVec2(-28,-49) * scale; + bStrut.vertices[1] = bzVec2(-28,-31.5) * scale; + shapes.add(rBody.createShape(bStrut)); + + // Bottom Wing + auto bWing = new bzPolyDef(density); + bWing.vertices.length = 4; + bWing.vertices[0] = bzVec2(-70,-49) * scale; + bWing.vertices[3] = bzVec2(28,-49) * scale; + bWing.vertices[2] = bzVec2(28,-70) * scale; + bWing.vertices[1] = bzVec2(-42,-70) * scale; + shapes.add(rBody.createShape(bWing)); + + rBody.setMassFromShapes(); + setPlanetGravity(); + } +} diff -r 82efafc87d54 -r 7f74e064dad5 steer.d --- a/steer.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,473 +0,0 @@ -/* - * Copyright (c) 2009, Mason Green (zzzzrrr) - * http://www.dsource.org/projects/openmelee - * Based on OpenSteer, Copyright (c) 2002-2003, Sony Computer Entertainment America - * Original author: Craig Reynolds - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the polygonal nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -module openmelee.steer; - -import blaze.common.bzMath: bzDot, bzClamp, bzVec2; -import blaze.dynamics.bzBody: bzBody; - -import openmelee.ship : Ship, State; -import openmelee.utilities; - -class Steer -{ - // Constructor: initializes state - this (Ship ship) - { - m_ship = ship; - } - - struct PathIntersection - { - bool intersect; - float distance; - bzVec2 surfacePoint; - bzVec2 surfaceNormal; - bzBody obstacle; - } - - // reset state - void reset () { - // initial state of wander behavior - m_wanderSide = 0; - m_wanderUp = 0; - } - - void update() { - m_position = m_ship.state.position; - m_velocity = m_ship.state.velocity; - m_speed = m_ship.state.speed; - m_maxForce = m_ship.state.maxForce; - m_forward = m_ship.state.forward; - } - - // -------------------------------------------------- steering behaviors - - bzVec2 steerForWander (float dt) { - // random walk m_wanderSide and m_wanderUp between -1 and +1 - float speed = 12 * dt; // maybe this (12) should be an argument? - m_wanderSide = scalarRandomWalk (m_wanderSide, speed, -1, +1); - m_wanderUp = scalarRandomWalk (m_wanderUp, speed, -1, +1); - - // return a pure lateral steering vector: (+/-Side) + (+/-Up) - return (m_side * m_wanderSide) + (m_up * m_wanderUp); - } - - // Seek behavior - bzVec2 steerForSeek (bzVec2 target) { - bzVec2 desiredVelocity = target - m_position; - return desiredVelocity - m_velocity; - } - - // Flee behavior - bzVec2 steerForFlee (bzVec2 target) { - bzVec2 desiredVelocity = m_position - target; - return desiredVelocity - m_velocity; - } - - /* - // xxx proposed, experimental new seek/flee [cwr 9-16-02] - bzVec2 xxxsteerForFlee (bzVec2 target) { - bzVec2 offset = m_position - target; - bzVec2 desiredVelocity = bzClamp(offset.truncateLength (maxSpeed ()); - return desiredVelocity - m_velocity; - } - - bzVec2 xxxsteerForSeek (bzVec2 target) { - // bzVec2 offset = target - position; - bzVec2 offset = target - m_position; - bzVec2 desiredVelocity = offset.truncateLength (maxSpeed ()); //xxxnew - return desiredVelocity - m_velocity; - } - */ - - /* - // ------------------------------------------------------------------------ - // Obstacle Avoidance behavior - // - // Returns a steering force to avoid a given obstacle. The purely - // lateral steering force will turn our vehicle towards a silhouette edge - // of the obstacle. Avoidance is required when (1) the obstacle - // intersects the vehicle's current path, (2) it is in front of the - // vehicle, and (3) is within minTimeToCollision seconds of travel at the - // vehicle's current velocity. Returns a zero vector value (bzVec2::zero) - // when no avoidance is required. - bzVec2 steerToAvoidObstacle (float minTimeToCollision, Obstacle obstacle) { - - bzVec2 avoidance = obstacle.steerToAvoid (this, minTimeToCollision); - return avoidance; - } - - // avoids all obstacles in an ObstacleGroup - */ - - bzVec2 steerToAvoidObstacles (float minTimeToCollision, bzBody obstacles) { - - bzVec2 avoidance; - PathIntersection nearest, next; - float minDistanceToCollision = minTimeToCollision * m_speed; - - next.intersect = false; - nearest.intersect = false; - - // test all obstacles for intersection with my forward axis, - // select the one whose point of intersection is nearest - for (bzBody o; o; o = o.next) { - // This code which presumes the obstacle is spherical - //findNextIntersectionWithSphere (o, next); - - if (!nearest.intersect || (next.intersect && next.distance < nearest.distance)) { - nearest = next; - } - } - - // when a nearest intersection was found - if (nearest.intersect && (nearest.distance < minDistanceToCollision)) { - // compute avoidance steering force: take offset from obstacle to me, - // take the component of that which is lateral (perpendicular to my - // forward direction), set length to maxForce, add a bit of forward - // component (in capture the flag, we never want to slow down) - bzVec2 offset = m_position - nearest.obstacle.position; - //avoidance = Vector3Helpers.PerpendicularComponent(offset, this.Forward); - avoidance.normalize; - avoidance *= m_maxForce; - avoidance += m_forward * m_maxForce * 0.75f; - } - - return avoidance; - } - - /* - // ------------------------------------------------------------------------ - // Unaligned collision avoidance behavior: avoid colliding with other - // nearby vehicles moving in unconstrained directions. Determine which - // (if any) other other vehicle we would collide with first, then steers - // to avoid the site of that potential collision. Returns a steering - // force vector, which is zero length if there is no impending collision. - - bzVec2 steerToAvoidNeighbors (float minTimeToCollision, AVGroup others) { - - // first priority is to prevent immediate interpenetration - bzVec2 separation = steerToAvoidCloseNeighbors (0, others); - if (separation != bzVec2::zero) return separation; - - // otherwise, go on to consider potential future collisions - float steer = 0; - Ship threat; - - // Time (in seconds) until the most immediate collision threat found - // so far. Initial value is a threshold: don't look more than this - // many frames into the future. - float minTime = minTimeToCollision; - - // xxx solely for annotation - bzVec2 xxxThreatPositionAtNearestApproach; - bzVec2 xxxOurPositionAtNearestApproach; - - // for each of the other vehicles, determine which (if any) - // pose the most immediate threat of collision. - for (AVIterator i = others.begin(); i != others.end(); i++) - { - Ship other = i; - if (other !is this) - { - // avoid when future positions are this close (or less) - float collisionDangerThreshold = radius * 2; - - // predicted time until nearest approach of "this" and "other" - float time = predictNearestApproachTime (other); - - // If the time is in the future, sooner than any other - // threatened collision... - if ((time >= 0) (time < minTime)) - { - // if the two will be close enough to collide, - // make a note of it - if (computeNearestApproachPositions (other, time) - < collisionDangerThreshold) - { - minTime = time; - threat = other; - xxxThreatPositionAtNearestApproach - = hisPositionAtNearestApproach; - xxxOurPositionAtNearestApproach - = ourPositionAtNearestApproach; - } - } - } - } - - // if a potential collision was found, compute steering to avoid - if (threat) - { - // parallel: +1, perpendicular: 0, anti-parallel: -1 - float parallelness = m_forward.dot(threat.forward); - float angle = 0.707f; - - if (parallelness < -angle) - { - // anti-parallel "head on" paths: - // steer away from future threat position - bzVec2 offset = xxxThreatPositionAtNearestApproach - m_position; - float sideDot = offset.dot(m_side()); - steer = (sideDot > 0) ? -1.0f : 1.0f; - } - else - { - if (parallelness > angle) - { - // parallel paths: steer away from threat - bzVec2 offset = threat.position - m_position; - float sideDot = bzDot(offset, m_side); - steer = (sideDot > 0) ? -1.0f : 1.0f; - } - else - { - // perpendicular paths: steer behind threat - // (only the slower of the two does this) - if (threat.speed() <= speed) - { - float sideDot = bzDot(m_side, threat.velocity); - steer = (sideDot > 0) ? -1.0f : 1.0f; - } - } - } - } - - return m_side() * steer; - } - */ - - // Given two vehicles, based on their current positions and velocities, - // determine the time until nearest approach - float predictNearestApproachTime (State other) { - - // imagine we are at the origin with no velocity, - // compute the relative velocity of the other vehicle - bzVec2 myVelocity = m_velocity; - bzVec2 otherVelocity = other.velocity; - bzVec2 relVelocity = otherVelocity - myVelocity; - float relSpeed = relVelocity.length; - - // for parallel paths, the vehicles will always be at the same distance, - // so return 0 (aka "now") since "there is no time like the present" - if (relSpeed == 0) return 0; - - // Now consider the path of the other vehicle in this relative - // space, a line defined by the relative position and velocity. - // The distance from the origin (our vehicle) to that line is - // the nearest approach. - - // Take the unit tangent along the other vehicle's path - bzVec2 relTangent = relVelocity / relSpeed; - - // find distance from its path to origin (compute offset from - // other to us, find length of projection onto path) - bzVec2 relPosition = m_position - other.position; - float projection = bzDot(relTangent, relPosition); - - return projection / relSpeed; - } - - // Given the time until nearest approach (predictNearestApproachTime) - // determine position of each vehicle at that time, and the distance - // between them - float computeNearestApproachPositions (State other, float time) { - - bzVec2 myTravel = m_forward * m_speed * time; - bzVec2 otherTravel = other.forward * other.speed * time; - - bzVec2 myFinal = m_position + myTravel; - bzVec2 otherFinal = other.position + otherTravel; - - return (myFinal - otherFinal).length; - } - - // ------------------------------------------------------------------------ - // pursuit of another vehicle ( version with ceiling on prediction time) - - bzVec2 steerForPursuit (State quarry) { - return steerForPursuit (quarry, float.max); - } - - bzVec2 steerForPursuit (State quarry, float maxPredictionTime) { - - // offset from this to quarry, that distance, unit vector toward quarry - bzVec2 offset = quarry.position - m_position; - float distance = offset.length; - bzVec2 unitOffset = offset / distance; - - // how parallel are the paths of "this" and the quarry - // (1 means parallel, 0 is pependicular, -1 is anti-parallel) - float parallelness = bzDot(m_forward , quarry.forward); - - // how "forward" is the direction to the quarry - // (1 means dead ahead, 0 is directly to the side, -1 is straight back) - float forwardness = bzDot(m_forward , unitOffset); - - float directTravelTime = distance / m_speed; - int f = intervalComparison (forwardness, -0.707f, 0.707f); - int p = intervalComparison (parallelness, -0.707f, 0.707f); - - float timeFactor = 0; // to be filled in below - - // Break the pursuit into nine cases, the cross product of the - // quarry being [ahead, aside, or behind] us and heading - // [parallel, perpendicular, or anti-parallel] to us. - switch (f) - { - case +1: - switch (p) - { - case +1: // ahead, parallel - timeFactor = 4; - break; - case 0: // ahead, perpendicular - timeFactor = 1.8f; - break; - case -1: // ahead, anti-parallel - timeFactor = 0.85f; - break; - } - break; - case 0: - switch (p) - { - case +1: // aside, parallel - timeFactor = 1; - break; - case 0: // aside, perpendicular - timeFactor = 0.8f; - break; - case -1: // aside, anti-parallel - timeFactor = 4; - break; - } - break; - case -1: - switch (p) - { - case +1: // behind, parallel - timeFactor = 0.5f; - break; - case 0: // behind, perpendicular - timeFactor = 2; - break; - case -1: // behind, anti-parallel - timeFactor = 2; - break; - } - break; - } - - // estimated time until intercept of quarry - float et = directTravelTime * timeFactor; - - // xxx experiment, if kept, this limit should be an argument - float etl = (et > maxPredictionTime) ? maxPredictionTime : et; - - // estimated position of quarry at intercept - bzVec2 target = quarry.predictFuturePosition(etl); - - return target; //steerForSeek (target); - } - - // ------------------------------------------------------------------------ - // evasion of another vehicle - bzVec2 steerForEvasion (State menace, float maxPredictionTime) { - - // offset from this to menace, that distance, unit vector toward menace - bzVec2 offset = menace.position - m_position; - float distance = offset.length; - - float roughTime = distance / menace.speed; - float predictionTime = ((roughTime > maxPredictionTime) ? maxPredictionTime : roughTime); - bzVec2 target = menace.predictFuturePosition (predictionTime); - - return steerForFlee (target); - } - - - // ------------------------------------------------------------------------ - // tries to maintain a given speed, returns a maxForce-clipped steering - // force along the forward/backward axis - bzVec2 steerForTargetSpeed (float targetSpeed) { - float mf = m_maxForce; - float speedError = targetSpeed - m_speed; - return m_forward * bzClamp(speedError, -mf, +mf); - } - - - // ----------------------------------------------------------- utilities - bool isAhead (bzVec2 target) {return isAhead (target, 0.707f);}; - bool isAside (bzVec2 target) {return isAside (target, 0.707f);}; - bool isBehind (bzVec2 target) {return isBehind (target, -0.707f);}; - - bool isAhead (bzVec2 target, float cosThreshold) - { - bzVec2 targetDirection = target - m_position; - targetDirection.normalize(); - return bzDot(m_forward, targetDirection) > cosThreshold; - } - - bool isAside (bzVec2 target, float cosThreshold) - { - bzVec2 targetDirection = target - m_position; - targetDirection.normalize(); - float dp = bzDot(m_forward, targetDirection); - return (dp < cosThreshold) && (dp > -cosThreshold); - } - - bool isBehind (bzVec2 target, float cosThreshold) - { - bzVec2 targetDirection = target - m_position; - targetDirection.normalize(); - return bzDot(m_forward, targetDirection) < cosThreshold; - } - - private: - - Ship m_ship; - - bzVec2 m_position; - bzVec2 m_velocity; - bzVec2 m_up; - bzVec2 m_side; - bzVec2 m_forward; - - float m_speed = 0; - float m_maxForce = 0; - - // Wander behavior - float m_wanderSide; - float m_wanderUp; -} diff -r 82efafc87d54 -r 7f74e064dad5 test/example.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/example.d Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,80 @@ +// jake -I../minid -I.. -version=old example.d +module example; + +import xf.xpose2.Expose; +import xf.xpose2.MiniD; +import tango.text.convert.Format; + +struct vec3 { + float x, y, z; + + char[] toString() { + return Format("x={} y={} z={}", x, y, z); + } + + mixin(xpose2(` + .* + toString + _ctor overload vec3 function(float, float, float) + `)); + mixin xposeMiniD; +} + +class Poop { + int x = 0; + + this() { + this.x = 123456; + } + + this(int x) { + this.x = x; + } + + this (char[] zomg) { + this.x = zomg.length; + } + + int max(int a, int b) { + return a > b ? a : b; + } + + int dmax(int a, int b) { + return max(max(a, b), x); + } + + int dmax(int a, int b, int c) { + return dmax(a, dmax(b, c)); + } + + vec3 getVec3(int x, int y, int z) { + return vec3(x, y, z); + } + +} + +mixin(xpose2(`Poop`,` + dmax + dmax overload int function(int, int, int) ; md { rename "dmax2" } + getVec3 + .* + _ctor + _ctor overload Poop function(int) + _ctor overload Poop function(char[]) +`)); + +mixin xposeMiniD!(`Poop`); + +void main(char[][] args) +{ + MDVM vm; + auto t = openVM(&vm); + loadStdlibs(t); + xposeMiniD_initAll(t); + superPush(t, new Poop(10)); + newGlobal(t, "poop"); + importModule(t, args[1]); + lookup(t, "poop"); + auto poop = superGet!(Poop)(t, -1); + Stdout.formatln("poop.dmax(1, 2) == {}", poop.dmax(1, 2)); +} diff -r 82efafc87d54 -r 7f74e064dad5 test/testScript.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testScript.md Wed Mar 25 11:28:25 2009 -0400 @@ -0,0 +1,25 @@ +module testscript + +local blah = vec3(1, 2, 30000) +writeln("created a vec3: ", blah) + +writeln("Hello world") +poop.x = 123 +writeln("poop.dmax2(1, 20, 150) == ", poop.dmax2(1, 20, 150)) +writeln("poop.dmax(1, 20) == ", poop.dmax(1, 20)) + +writeln("getting a vec3...") +local v3 = poop.getVec3(3, 6, 9) +writeln("x = ", v3.x, " y = ", v3.y, " z = ", v3.z) + +class Zomg : Poop { + /+this() { + super(1, 2, 3) + }+/ + + function dmax(a : int, b : int) { + return 1337 + } +} + +poop = Zomg() diff -r 82efafc87d54 -r 7f74e064dad5 testScript.md --- a/testScript.md Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -module testscript - -local blah = vec3(1, 2, 30000) -writeln("created a vec3: ", blah) - -writeln("Hello world") -poop.x = 123 -writeln("poop.dmax2(1, 20, 150) == ", poop.dmax2(1, 20, 150)) -writeln("poop.dmax(1, 20) == ", poop.dmax(1, 20)) - -writeln("getting a vec3...") -local v3 = poop.getVec3(3, 6, 9) -writeln("x = ", v3.x, " y = ", v3.y, " z = ", v3.z) - -class Zomg : Poop { - /+this() { - super(1, 2, 3) - }+/ - - function dmax(a : int, b : int) { - return 1337 - } -} - -poop = Zomg() diff -r 82efafc87d54 -r 7f74e064dad5 urQuan.d --- a/urQuan.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2009, Mason Green (zzzzrrr) - * http://www.dsource.org/projects/openmelee - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the polygonal nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -module openmelee.urQuan; - -import blaze.dynamics.bzBody : bzBody; -import blaze.bzWorld: bzWorld; -import blaze.dynamics.bzBodyDef; -import blaze.collision.shapes.bzPolygon : bzPolyDef; -import blaze.common.bzMath: bzVec2; - -import openmelee.ship; - -// UrQuan Dreadnought -class UrQuan : Ship -{ - - float scale = 0.025; - - this(bzWorld world) { - - super(world); - engineForce = bzVec2(500, 0); - turnForce = bzVec2(0, 9000); - rightTurnPoint = bzVec2(-0.5, 0); - leftTurnPoint = bzVec2(0.5, 0); - - auto bodyDef = new bzBodyDef; - //bodyDef.isBullet = true; - bodyDef.position = bzVec2(30,5); - bodyDef.allowFreeze = false; - rBody = world.createBody(bodyDef); - float density = 5.0f; - - // Head - auto head = new bzPolyDef; - head.vertices.length = 8; - head.vertices[0] = bzVec2(42,49) * scale; - head.vertices[7] = bzVec2(63,49) * scale; - head.vertices[6] = bzVec2(70,45.5) * scale; - head.vertices[5] = bzVec2(73.5,38.5) * scale; - head.vertices[4] = bzVec2(73.5,-42) * scale; - head.vertices[3] = bzVec2(70,-49) * scale; - head.vertices[2] = bzVec2(63,-56) * scale; - head.vertices[1] = bzVec2(42,-56) * scale; - shapes.add(rBody.createShape(head)); - - // Body - auto b = new bzPolyDef(density); - b.vertices.length = 4; - b.vertices[0] = bzVec2(-70,-28) * scale; - b.vertices[3] = bzVec2(-70,24.5) * scale; - b.vertices[2] = bzVec2(42,24.5) * scale; - b.vertices[1] = bzVec2(42,-31.5) * scale; - shapes.add(rBody.createShape(b)); - - // Top Strut - auto tStrut = new bzPolyDef(density); - tStrut.vertices.length = 4; - tStrut.vertices[0] = bzVec2(0,24.5) * scale; - tStrut.vertices[3] = bzVec2(-28,24.5) * scale; - tStrut.vertices[2] = bzVec2(-28,42) * scale; - tStrut.vertices[1] = bzVec2(0,42) * scale; - shapes.add(rBody.createShape(tStrut)); - - // Top Wing - auto tWing = new bzPolyDef(density); - tWing.vertices.length = 4; - tWing.vertices[0] = bzVec2(-70,42) * scale; - tWing.vertices[3] = bzVec2(-49,63) * scale; - tWing.vertices[2] = bzVec2(28,63) * scale; - tWing.vertices[1] = bzVec2(28,42) * scale; - shapes.add(rBody.createShape(tWing)); - - // Bottom Strut - auto bStrut = new bzPolyDef(density); - bStrut.vertices.length = 4; - bStrut.vertices[0] = bzVec2(0,-31.5) * scale; - bStrut.vertices[3] = bzVec2(0,-49) * scale; - bStrut.vertices[2] = bzVec2(-28,-49) * scale; - bStrut.vertices[1] = bzVec2(-28,-31.5) * scale; - shapes.add(rBody.createShape(bStrut)); - - // Bottom Wing - auto bWing = new bzPolyDef(density); - bWing.vertices.length = 4; - bWing.vertices[0] = bzVec2(-70,-49) * scale; - bWing.vertices[3] = bzVec2(28,-49) * scale; - bWing.vertices[2] = bzVec2(28,-70) * scale; - bWing.vertices[1] = bzVec2(-42,-70) * scale; - shapes.add(rBody.createShape(bWing)); - - rBody.setMassFromShapes(); - setPlanetGravity(); - } -} diff -r 82efafc87d54 -r 7f74e064dad5 utilities.d --- a/utilities.d Tue Mar 24 16:47:42 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2009, Mason Green (zzzzrrr) - * http://www.dsource.org/projects/openmelee - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of the polygonal nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -module openmelee.utilities; - -import tango.math.random.Kiss : Kiss; - -float scalarRandomWalk(float initial, float walkspeed, float min, float max) { - - float next = initial + (((randomRange(0, 1) * 2) - 1) * walkspeed); - if (next < min) return min; - if (next > max) return max; - return next; -} - -// ---------------------------------------------------------------------------- -// classify a value relative to the interval between two bounds: -// returns -1 when below the lower bound -// returns 0 when between the bounds (inside the interval) -// returns +1 when above the upper bound -int intervalComparison(float x, float lowerBound, float upperBound) -{ - if (x < lowerBound) return -1; - if (x > upperBound) return +1; - return 0; -} - -T randomRange(T = int) (T min, T max) -{ - return min + Kiss.instance.natural() % (max + 1 - min); -}