Exemple #1
0
        private void CreateEntities()
        {
            var tiledMap = content.Load <TiledMap>(_settings.MapTile);

            String[] tiledMapLayers = new[]
            {
                TiledImportCollisionLayers.BACK_WALLS, TiledImportCollisionLayers.SIDE_WALLS, TiledImportCollisionLayers.NET
            };
            int[] tiledMapPhysicsLayers = new[]
            {
                PhysicsLayers.BACK_WALLS, PhysicsLayers.SIDE_WALLS, PhysicsLayers.NET
            };
            var tiledMapComponent = new Handy.Components.TiledMapComponent(tiledMap, tiledMapLayers, tiledMapPhysicsLayers, true);
            var entity            = new Entity();

            entity.name = "Map";
            tiledMapComponent.renderLayer = RenderLayers.BACKGROUND;
            entity.addComponent(tiledMapComponent);
            addEntity(entity);

            var gameState = new GameState();

            gameState.StateEnum = GameStates.Ready;
            gameState.Players   = new Player.Player[_settings.NumPlayers];
            for (var i = 0; i < _settings.NumPlayers; i++)
            {
                var playerSettings = _settings.Players[i];
                var player         = new Player.Player(playerSettings);
                addEntity(player);
                gameState.Players[i] = player;
            }

            var ball = new Ball.Ball();

            addEntity(ball);
            gameState.Ball = ball;

            GameStateEntity      = new Entity();
            GameStateEntity.name = "Game";
            GameStateEntity.addComponent(new GameStateComponent(gameState));
            GameStateEntity.addComponent(new TimerComponent());
            GameStateEntity.addComponent(new HitStopComponent());
            var scoreboard = new UICanvas();

            scoreboard.name        = "scoreboard";
            scoreboard.renderLayer = RenderLayers.FOREGROUND;
            GameStateEntity.addComponent(scoreboard);
            addEntity(GameStateEntity);

            // add camera
            var cam         = new Camera();
            var cameraShake = new CameraShakeComponent();

            CameraEntity.addComponent(cam);
            CameraEntity.addComponent(cameraShake);
            CameraEntity.name = "Camera";
            addEntity(CameraEntity);
        }
Exemple #2
0
 public void ThrowBall()
 {
     CarryBall.transform.position = transform.position + _throwOffset.Scale((int)Context.Direction, 1f).ToVector3();
     if (Context.Direction == Direction.Right)
     {
         CarryBall.TriggerState <Ball.ThrowedRightState>();
     }
     else
     {
         CarryBall.TriggerState <Ball.ThrowedLeftState>();
     }
     CarryBall.EnableCollider();
     CarryBall = null;
 }
Exemple #3
0
        protected virtual void CreateBall()
        {
            var ballPrefab = GetBallPrefab();

            _ballGO = Instantiate(ballPrefab, ballStartPosition.position, Quaternion.identity);
            _ball   = _ballGO.GetComponent <Ball.Ball>();
            var randomService = new RandomUnityService();

            _ball.ballMovement   = new BallMovement(_ball.speed, randomService, ballData.minSpeed, ballData.maxSpeed);
            _ball.ballAppearance = new BallAppearance(_ball.GetComponentInChildren <SpriteRenderer>(),
                                                      randomService,
                                                      _ball.transform,
                                                      ballData.minSize,
                                                      ballData.maxSize,
                                                      _settingsProvider.GetBallColor());
        }
Exemple #4
0
        public override float HitTest(Ball.Ball ball, float dTime, CollisionEvent coll, PlayerPhysics physics)
        {
            if (!_data.IsEnabled)
            {
                return(-1.0f);
            }

            var lastFace = _mover.LastHitFace;

            // for effective computing, adding a last face hit value to speed calculations
            // a ball can only hit one face never two
            // also if a ball hits a face then it can not hit either radius
            // so only check these if a face is not hit
            // endRadius is more likely than baseRadius ... so check it first

            var hitTime = HitTestFlipperFace(ball, dTime, coll, lastFace);             // first face

            if (hitTime >= 0)
            {
                return(hitTime);
            }

            hitTime = HitTestFlipperFace(ball, dTime, coll, !lastFace);             //second face
            if (hitTime >= 0)
            {
                _mover.LastHitFace = !lastFace;                 // change this face to check first // HACK
                return(hitTime);
            }

            hitTime = HitTestFlipperEnd(ball, dTime, coll);             // end radius
            if (hitTime >= 0)
            {
                return(hitTime);
            }

            hitTime = _mover.HitCircleBase.HitTest(ball, dTime, coll, physics);
            if (hitTime >= 0)
            {
                // Tangent velocity of contact point (rotate Normal right)
                // rad units*d/t (Radians*diameter/time)
                coll.HitVel.Set(0, 0);
                coll.HitMomentBit = true;
                return(hitTime);
            }

            return(-1.0f);            // no hits
        }
Exemple #5
0
        private void GetRelativeVelocity(Vertex3D normal, Ball.Ball ball, Vertex3D vRel, Vertex3D rB, Vertex3D rF)
        {
            rB.Set(normal.Clone().MultiplyScalar(-ball.Data.Radius));
            var hitPos = ball.State.Pos.Clone().Add(rB);

            var cF = new Vertex3D(
                _mover.HitCircleBase.Center.X,
                _mover.HitCircleBase.Center.Y,
                ball.State.Pos.Z                 // make sure collision happens in same z plane where ball is
                );

            rF.Set(hitPos.Clone().Sub(cF));             // displacement relative to flipper center
            var vB = ball.Hit.SurfaceVelocity(rB);
            var vF = _mover.SurfaceVelocity(rF);

            vRel.Set(vB.Clone().Sub(vF));
        }
        private void ResetBall(Ball.Ball ball, Gameplay.Side side)
        {
            var ballState = ball.getComponent <BallStateComponent>();

            ballState.LastHitSide   = Gameplay.Side.NONE;
            ballState.HitBoost      = 1.0f;
            ballState.IsDeadly      = false;
            ballState.BaseSpeed     = ballState.BaseSpeedInitial;
            ballState.IsBeingServed = true;
            if (side == Gameplay.Side.LEFT ||
                (side == Gameplay.Side.NONE))  // && Random.chance(0.5f)
            {
                ball.position = BallResetPositions.LEFT_RESET;
            }
            else
            {
                ball.position = BallResetPositions.RIGHT_RESET;
            }

            ball.getComponent <VelocityComponent>().Freeze = true;
        }
 public override float HitTest(Ball.Ball ball, float dTime, CollisionEvent coll, PlayerPhysics physics)
 {
     // not needed in unity ECS
     throw new System.NotImplementedException();
 }
Exemple #8
0
        private float HitTestFlipperEnd(Ball.Ball ball, float dTime, CollisionEvent coll)
        {
            var angleCur   = _state.Angle;
            var angleSpeed = _mover.AngleSpeed;             // rotation rate

            var flipperBase = _mover.HitCircleBase.Center;

            var angleMin = MathF.Min(_mover.AngleStart, _mover.AngleEnd);
            var angleMax = MathF.Max(_mover.AngleStart, _mover.AngleEnd);

            var ballRadius = ball.Data.Radius;
            var feRadius   = _mover.EndRadius;

            var ballEndRadius = feRadius + ballRadius;             // magnititude of (ball - flipperEnd)

            var ballX = ball.State.Pos.X;
            var ballY = ball.State.Pos.Y;

            var ballVx = ball.Hit.Vel.X;
            var ballVy = ball.Hit.Vel.Y;

            var vp = new Vertex2D(
                0.0f,                 // m_flipperradius * sin(0);
                -_mover.FlipperRadius // m_flipperradius * (-cos(0));
                );

            float ballVtx    = 0;
            float ballVty    = 0;          // new ball position at time t in flipper face coordinate
            float contactAng = 0;
            float bFend      = 0;
            float cbceDist   = 0;
            float t0         = 0;
            float t1         = 0;
            float d0         = 0;
            float d1         = 0;
            float dp         = 0;

            // start first interval ++++++++++++++++++++++++++
            float t = 0;
            int   k;

            for (k = 1; k <= PhysicsConstants.Internations; ++k)
            {
                // determine flipper rotation direction, limits and parking
                contactAng = angleCur + angleSpeed * t;                 // angle at time t

                if (contactAng >= angleMax)
                {
                    contactAng = angleMax;                     // stop here
                }
                else if (contactAng <= angleMin)
                {
                    contactAng = angleMin;                     // stop here
                }

                var radSin = MathF.Sin(contactAng);                 // Green"s transform matrix... rotate angle delta
                var radCos = MathF.Cos(contactAng);                 // rotational transform from zero position to position at time t

                // rotate angle delta unit vector, rotates system according to flipper face angle
                var vt = new Vertex2D(
                    vp.X * radCos - vp.Y * radSin + flipperBase.X,                     // rotate and translate to world position
                    vp.Y * radCos + vp.X * radSin + flipperBase.Y
                    );

                ballVtx = ballX + ballVx * t - vt.X;                 // new ball position relative to flipper end radius
                ballVty = ballY + ballVy * t - vt.Y;

                // center ball to center end radius distance
                cbceDist = MathF.Sqrt(ballVtx * ballVtx + ballVty * ballVty);

                // ball face-to-radius surface distance
                bFend = cbceDist - ballEndRadius;

                if (MathF.Abs(bFend) <= PhysicsConstants.Precision)
                {
                    break;
                }

                if (k == 1)
                {
                    // end of pass one ... set full interval pass, t = dtime
                    // test for extreme conditions
                    if (bFend < -(ball.Data.Radius + feRadius))
                    {
                        // too deeply embedded, ambiguous position
                        return(-1.0f);
                    }

                    if (bFend <= PhysicsConstants.PhysTouch)
                    {
                        // inside the clearance limits
                        break;
                    }

                    // set for second pass, force t=dtime
                    t0 = t1 = dTime;
                    d0 = 0;
                    d1 = bFend;
                }
                else if (k == 2)
                {
                    // end pass two, check if zero crossing on initial interval, exit if none
                    if (dp * bFend > 0.0)
                    {
                        // no solution ... no obvious zero crossing
                        return(-1.0f);
                    }

                    t0 = 0;
                    t1 = dTime;
                    d0 = dp;
                    d1 = bFend;                     // set initial boundaries
                }
                else
                {
                    // (k >= 3) // MFP root search
                    if (bFend * d0 <= 0.0)
                    {
                        // zero crossing
                        t1 = t;
                        d1 = bFend;
                        if (dp * bFend > 0)
                        {
                            d0 *= 0.5f;
                        }
                    }
                    else
                    {
                        t0 = t;
                        d0 = bFend;
                        if (dp * bFend > 0)
                        {
                            d1 *= 0.5f;
                        }
                    }                     // move left interval limit
                }

                t  = t0 - d0 * (t1 - t0) / (d1 - d0); // estimate next t
                dp = bFend;                           // remember
            }

            //+++ End time interaction loop found time t solution ++++++

            // time is outside this frame ... no collision
            if (float.IsNaN(t) || float.IsInfinity(t) || t < 0 || t > dTime ||
                k > PhysicsConstants.Internations && MathF.Abs(bFend) > ball.Data.Radius * 0.25)
            {
                // last ditch effort to accept a solution
                return(-1.0f);                // no solution
            }

            // here ball and flipper end are in contact .. well in most cases, near and embedded solutions need calculations
            var hitZ = ball.State.Pos.Z + ball.Hit.Vel.Z * t;             // check for a hole, relative to ball rolling point at hittime

            // check limits of object"s height and depth
            if (hitZ + ballRadius * 0.5 < HitBBox.ZLow || hitZ - ballRadius * 0.5 > HitBBox.ZHigh)
            {
                return(-1.0f);
            }

            // ok we have a confirmed contact, calc the stats, remember there are "near" solution, so all
            // parameters need to be calculated from the actual configuration, i.E. contact radius must be calc"ed
            var invCbceDist = 1.0f / cbceDist;

            coll.HitNormal.Set(
                ballVtx * invCbceDist,                 // normal vector from flipper end to ball
                ballVty * invCbceDist,
                0.0f
                );

            // vector from base to flipperEnd plus the projected End radius
            var dist = new Vertex2D(
                ball.State.Pos.X + ballVx * t - ballRadius * coll.HitNormal.X - _mover.HitCircleBase.Center.X,
                ball.State.Pos.Y + ballVy * t - ballRadius * coll.HitNormal.Y - _mover.HitCircleBase.Center.Y
                );

            // distance from base center to contact point
            var distance = MathF.Sqrt(dist.X * dist.X + dist.Y * dist.Y);

            // hit limits ???
            if (contactAng >= angleMax && angleSpeed > 0 || contactAng <= angleMin && angleSpeed < 0)
            {
                angleSpeed = 0;                 // rotation stopped
            }

            // Unit Tangent vector velocity of contact point(rotate normal right)
            var invDistance = 1.0f / distance;

            coll.HitVel.Set(-dist.Y * invDistance, dist.X * invDistance);
            coll.HitMomentBit = distance == 0;

            // recheck using actual contact angle of velocity direction
            var dv = new Vertex2D(
                ballVx - coll.HitVel.X * angleSpeed * distance,                 // delta velocity ball to face
                ballVy - coll.HitVel.Y * angleSpeed * distance
                );

            var bnv = dv.X * coll.HitNormal.X + dv.Y * coll.HitNormal.Y;             // dot Normal to delta v

            if (bnv >= 0)
            {
                // not hit ... ball is receding from face already, must have been embedded or shallow angled
                return(-1.0f);
            }

            if (MathF.Abs(bnv) <= PhysicsConstants.ContactVel && bFend <= PhysicsConstants.PhysTouch)
            {
                coll.IsContact            = true;
                coll.HitOrgNormalVelocity = bnv;
            }

            coll.HitDistance = bFend;             // actual contact distance ..

            return(t);
        }
Exemple #9
0
        public float HitTestFlipperFace(Ball.Ball ball, float dTime, CollisionEvent coll, bool face1)
        {
            var angleCur   = _state.Angle;
            var angleSpeed = _mover.AngleSpeed;             // rotation rate

            var flipperBase = _mover.HitCircleBase.Center;
            var feRadius    = _mover.EndRadius;

            var angleMin = MathF.Min(_mover.AngleStart, _mover.AngleEnd);
            var angleMax = MathF.Max(_mover.AngleStart, _mover.AngleEnd);

            var ballRadius = ball.Data.Radius;
            var ballVx     = ball.Hit.Vel.X;
            var ballVy     = ball.Hit.Vel.Y;

            // flipper positions at zero degrees rotation
            var ffnx = _mover.ZeroAngNorm.X;             // flipper face normal vector //Face2

            if (face1)
            {
                // negative for face1 (left face)
                ffnx = -ffnx;
            }

            var ffny = _mover.ZeroAngNorm.Y;        // norm y component same for either face
            var vp   = new Vertex2D(                // face segment V1 point
                _mover.HitCircleBase.Radius * ffnx, // face endpoint of line segment on base radius
                _mover.HitCircleBase.Radius * ffny
                );

            var faceNormal = new Vertex2D(); // flipper face normal

            float bffnd      = 0;            // ball flipper face normal distance (negative for normal side)
            float ballVtx    = 0;            // new ball position at time t in flipper face coordinate
            float ballVty    = 0;
            float contactAng = 0;

            // Modified False Position control
            float t  = 0;
            float t0 = 0;
            float t1 = 0;
            float d0 = 0;
            float d1 = 0;
            float dp = 0;

            // start first interval ++++++++++++++++++++++++++
            int k;

            for (k = 1; k <= PhysicsConstants.Internations; ++k)
            {
                // determine flipper rotation direction, limits and parking
                contactAng = angleCur + angleSpeed * t;                 // angle at time t

                if (contactAng >= angleMax)
                {
                    // stop here
                    contactAng = angleMax;
                }
                else if (contactAng <= angleMin)
                {
                    // stop here
                    contactAng = angleMin;
                }

                var radSin = MathF.Sin(contactAng);                 // Green"s transform matrix... rotate angle delta
                var radCos = MathF.Cos(contactAng);                 // rotational transform from current position to position at time t

                faceNormal.X = ffnx * radCos - ffny * radSin;       // rotate to time t, norm and face offset point
                faceNormal.Y = ffny * radCos + ffnx * radSin;

                var vt = new Vertex2D(
                    vp.X * radCos - vp.Y * radSin + flipperBase.X,                     // rotate and translate to world position
                    vp.Y * radCos + vp.X * radSin + flipperBase.Y
                    );

                ballVtx = ball.State.Pos.X + ballVx * t - vt.X;                 // new ball position relative to rotated line segment endpoint
                ballVty = ball.State.Pos.Y + ballVy * t - vt.Y;

                bffnd = ballVtx * faceNormal.X + ballVty * faceNormal.Y - ballRadius;                 // normal distance to segment

                if (MathF.Abs(bffnd) <= PhysicsConstants.Precision)
                {
                    break;
                }

                // loop control, boundary checks, next estimate, etc.
                if (k == 1)
                {
                    // end of pass one ... set full interval pass, t = dtime

                    // test for already inside flipper plane, either embedded or beyond the face endpoints
                    if (bffnd < -(ball.Data.Radius + feRadius))
                    {
                        return(-1.0f);                        // wrong side of face, or too deeply embedded
                    }

                    if (bffnd <= PhysicsConstants.PhysTouch)
                    {
                        break;                         // inside the clearance limits, go check face endpoints
                    }

                    t0 = t1 = dTime;
                    d0 = 0;
                    d1 = bffnd;                     // set for second pass, so t=dtime
                }
                else if (k == 2)
                {
                    // end pass two, check if zero crossing on initial interval, exit
                    if (dp * bffnd > 0.0)
                    {
                        return(-1.0f);                        // no solution ... no obvious zero crossing
                    }

                    t0 = 0;
                    t1 = dTime;
                    d0 = dp;
                    d1 = bffnd;                     // testing MFP estimates
                }
                else
                {
                    // (k >= 3)                           // MFP root search +++++++++++++++++++++++++++++++++++++++++
                    if (bffnd * d0 <= 0.0)
                    {
                        // zero crossing
                        t1 = t;
                        d1 = bffnd;
                        if (dp * bffnd > 0.0)
                        {
                            d0 *= 0.5f;
                        }
                    }
                    else
                    {
                        // move right limits
                        t0 = t;
                        d0 = bffnd;
                        if (dp * bffnd > 0.0)
                        {
                            d1 *= 0.5f;
                        }
                    }                     // move left limits
                }

                t  = t0 - d0 * (t1 - t0) / (d1 - d0); // next estimate
                dp = bffnd;                           // remember
            }

            // +++ End time iteration loop found time t soultion ++++++
            if (float.IsNaN(t) || float.IsInfinity(t) ||
                t < 0 ||
                t > dTime ||                            // time is outside this frame ... no collision
                k > PhysicsConstants.Internations && MathF.Abs(bffnd) > ball.Data.Radius * 0.25)
            {
                // last ditch effort to accept a near solution

                return(-1.0f);                // no solution
            }

            // here ball and flipper face are in contact... past the endpoints, also, don"t forget embedded and near solution
            var faceTangent = new Vertex2D();             // flipper face tangent

            if (face1)
            {
                // left face?
                faceTangent.X = -faceNormal.Y;
                faceTangent.Y = faceNormal.X;
            }
            else
            {
                // rotate to form Tangent vector
                faceTangent.X = faceNormal.Y;
                faceTangent.Y = -faceNormal.X;
            }

            var bfftd = ballVtx * faceTangent.X + ballVty * faceTangent.Y;     // ball to flipper face tangent distance

            var len = _mover.FlipperRadius * _mover.ZeroAngNorm.X;             // face segment length ... e.G. same on either face

            if (bfftd < -PhysicsConstants.ToleranceEndPoints || bfftd > len + PhysicsConstants.ToleranceEndPoints)
            {
                return(-1.0f);                // not in range of touching
            }

            var hitZ = ball.State.Pos.Z + ball.Hit.Vel.Z * t;             // check for a hole, relative to ball rolling point at hittime

            // check limits of object"s height and depth
            if (hitZ + ballRadius * 0.5 < HitBBox.ZLow || hitZ - ballRadius * 0.5 > HitBBox.ZHigh)
            {
                return(-1.0f);
            }

            // ok we have a confirmed contact, calc the stats, remember there are "near" solution, so all
            // parameters need to be calculated from the actual configuration, i.E contact radius must be calc"ed

            // hit normal is same as line segment normal
            coll.HitNormal.Set(faceNormal.X, faceNormal.Y, 0);

            var dist = new Vertex2D(             // calculate moment from flipper base center
                ball.State.Pos.X + ballVx * t - ballRadius * faceNormal.X -
                _mover.HitCircleBase.Center.X,   // center of ball + projected radius to contact point
                ball.State.Pos.Y + ballVy * t - ballRadius * faceNormal.Y -
                _mover.HitCircleBase.Center.Y    // all at time t
                );

            var distance = MathF.Sqrt(dist.X * dist.X + dist.Y * dist.Y);             // distance from base center to contact point

            var invDist = 1.0f / distance;

            coll.HitVel.Set(-dist.Y * invDist,
                            dist.X * invDist);     // Unit Tangent velocity of contact point(rotate Normal clockwise)
            //coll.Hitvelocity.Z = 0.0f; // used as normal velocity so far, only if isContact is set, see below

            if (contactAng >= angleMax && angleSpeed > 0 || contactAng <= angleMin && angleSpeed < 0)
            {
                // hit limits ???
                angleSpeed = 0.0f;                 // rotation stopped
            }

            coll.HitMomentBit = distance == 0;

            var dv = new Vertex2D(             // delta velocity ball to face
                ballVx - coll.HitVel.X * angleSpeed * distance,
                ballVy - coll.HitVel.Y * angleSpeed * distance
                );

            var bnv = dv.X * coll.HitNormal.X + dv.Y * coll.HitNormal.Y;             // dot Normal to delta v

            if (MathF.Abs(bnv) <= PhysicsConstants.ContactVel && bffnd <= PhysicsConstants.PhysTouch)
            {
                coll.IsContact            = true;
                coll.HitOrgNormalVelocity = bnv;
            }
            else if (bnv > PhysicsConstants.LowNormVel)
            {
                return(-1.0f);                // not hit ... ball is receding from endradius already, must have been embedded
            }

            coll.HitDistance = bffnd;             // normal ...Actual contact distance ...
            //coll.M_hitRigid = true;                               // collision type

            return(t);
        }
Exemple #10
0
 public void PickUpBall(Ball.Ball ball)
 {
     CarryBall = ball;
     CarryBall.TriggerState <Ball.IdleState>();
     ball.DisableCollider();
 }
Exemple #11
0
 public void ThrowBallUp()
 {
     CarryBall.TriggerState <Ball.JumpState>();
     CarryBall.EnableCollider();
     CarryBall = null;
 }
Exemple #12
0
 public void DropBall()
 {
     CarryBall.TriggerState <Ball.BounceState>();
     CarryBall.EnableCollider();
     CarryBall = null;
 }
Exemple #13
0
 public void OnBallCreated(PlayerPhysics physics, Ball.Ball ball)
 {
     ball.Coll.HitFlag = true;                                                                 // HACK: avoid capture leaving kicker
     var hitNormal = new Vertex3D(Constants.FloatMax, Constants.FloatMax, Constants.FloatMax); // unused due to newBall being true
     // TODO this.hit!.doCollide(physics, ball, hitNormal, false, true);
 }
 private void ResetForService(Ball.Ball ball, Player.Player[] players, Gameplay.Side side)
 {
     ResetBall(ball, side);
     ResetPlayers(players);
 }