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); }
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; }
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()); }
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 }
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(); }
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); }
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); }
public void PickUpBall(Ball.Ball ball) { CarryBall = ball; CarryBall.TriggerState <Ball.IdleState>(); ball.DisableCollider(); }
public void ThrowBallUp() { CarryBall.TriggerState <Ball.JumpState>(); CarryBall.EnableCollider(); CarryBall = null; }
public void DropBall() { CarryBall.TriggerState <Ball.BounceState>(); CarryBall.EnableCollider(); CarryBall = null; }
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); }