Skip to content

Commit

Permalink
Minor refactoring, add counting collisions with objects in one tick, …
Browse files Browse the repository at this point in the history
…also add test for check this counter
  • Loading branch information
evgTSV committed Jan 13, 2025
1 parent 9336cd6 commit 752c91c
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 26 deletions.
2 changes: 1 addition & 1 deletion O21.Game/Animations/PlayerAnimation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ type PlayerAnimation = {
| None -> this.AnimationQueue.Tail
| Some updated -> updated :: this.AnimationQueue.Tail

if Seq.exists ((=) AnimationType.Die) animations then
if Array.contains AnimationType.Die animations then
queue <- this.ExplosionAnimation tick :: queue

{ this with
Expand Down
26 changes: 15 additions & 11 deletions O21.Game/Engine/Entities.fs
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,18 @@ type Player = {
let level = playerEnv.Level
let enemies = playerEnv.EnemyColliders

let scores = this.CalculateScores(playerEnv)
let scores = this.CalculateScoreChange(playerEnv)
let newPlayer = { this with Scores = Math.Max(this.Scores + scores, 0) }

if this.Oxygen.IsEmpty then PlayerEffect.Die
else
match CheckCollision level this.Box enemies with
| Collision.OutOfBounds -> PlayerEffect.Update this // TODO[#28]: Level progression
| Collision.CollidesBrick -> PlayerEffect.Die
| Collision.CollidesBox -> PlayerEffect.Die
| Collision.CollidesObject _ -> PlayerEffect.Die
| Collision.None -> PlayerEffect.Update newPlayer

member private this.CalculateScores(playerEnv: PlayerEnv) =
member private this.CalculateScoreChange(playerEnv: PlayerEnv) =
this.ScoresFromShot(playerEnv)

member private this.ScoresFromShot(playerEnv: PlayerEnv) =
Expand All @@ -69,13 +69,17 @@ type Player = {
let enemies = playerEnv.EnemyColliders
let bonuses = playerEnv.BonusColliders

let isCollides b boxes = (CheckCollision level b boxes).IsCollidesBox
let countCollision b boxes =
match CheckCollision level b boxes with
| Collision.CollidesObject count -> count | _ -> 0

bullets
|> Array.fold (fun acc b ->
let plus = if isCollides b enemies then GameRules.GiveScoresForBomb else 0 // TODO: Split bomb and fish collision check
let subtract = if isCollides b bonuses then GameRules.SubtractScoresForShotBonus else 0
acc + plus - subtract) 0
(0, bullets)
||> Array.fold (fun acc b ->
let plus =
countCollision b enemies * GameRules.GiveScoresForBomb // TODO: Split bomb and fish collision check
let subtract =
countCollision b bonuses * GameRules.SubtractScoresForShotBonus
acc + plus - subtract)

static member Default = {
TopLeft = GameRules.PlayerStartingPosition
Expand Down Expand Up @@ -211,7 +215,7 @@ type Bomb = {
else
this
match CheckCollision level updated.Box allEntities with
| Collision.CollidesBox -> EnemyEffect.PlayerHit this.Id
| Collision.CollidesObject _ -> EnemyEffect.PlayerHit this.Id
| Collision.None -> EnemyEffect.Update updated
| _ -> EnemyEffect.Die
| BombState.Active velocity ->
Expand All @@ -223,7 +227,7 @@ type Bomb = {
{ this with
TopLeft = this.TopLeft + velocity * timeDelta }
match CheckCollision level this.Box allEntities with
| Collision.CollidesBox -> EnemyEffect.PlayerHit this.Id
| Collision.CollidesObject _ -> EnemyEffect.PlayerHit this.Id
| Collision.None -> EnemyEffect.Update newBomb
| _ -> EnemyEffect.Die
else
Expand Down
2 changes: 1 addition & 1 deletion O21.Game/Engine/GameField.fs
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,4 @@ type Collision =
/// At least one pixel of the object intersects with a brick.
| CollidesBrick
/// Tells, that the object collides other box\boxes in its environment
| CollidesBox
| CollidesObject of count: int
23 changes: 13 additions & 10 deletions O21.Game/Engine/Geometry.fs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ let private IsOutOfBounds (box: Box) =
|| box.TopLeft.Y <= 0 && box.TopLeft.Y + box.Size.Y <= 0
|| box.TopLeft.Y >= GameRules.LevelHeight && box.TopLeft.Y + box.Size.Y >= GameRules.LevelHeight

let private IsCollidesBricks (level: Level) (box: Box) =
let private HasBrickCollision (level: Level) (box: Box) =
let getCell(Point(x, y)) =
let cellX = Math.Clamp(x / GameRules.BrickSize.X, 0, level.LevelMap[0].Length - 1)
let cellY = Math.Clamp(y / GameRules.BrickSize.Y, 0, level.LevelMap.Length - 1)
Expand All @@ -29,7 +29,7 @@ let private IsCollidesBricks (level: Level) (box: Box) =
|| isBrickCell box.BottomLeft
|| isBrickCell box.BottomRight

let private IsBoxCollides (fst: Box) (snd: Box) =
let private HasBoxCollision (fst: Box) (snd: Box) =
not ( fst.TopRight.X < snd.TopLeft.X
|| fst.TopLeft.X > snd.TopRight.X
|| fst.BottomRight.Y < snd.TopLeft.Y
Expand All @@ -40,18 +40,21 @@ let private IsBoxCollides (fst: Box) (snd: Box) =
|| snd.BottomRight.Y < fst.TopLeft.Y
|| snd.TopLeft.Y > fst.BottomRight.Y)

let private IsBoxCollidesOther (otherBoxes: Box[]) (box: Box) =
Array.exists (IsBoxCollides box) otherBoxes
let private IsBoxCollidesOther (otherBoxes: Box[]) (collisionCount: int outref) (box: Box) =
let count = Array.filter (HasBoxCollision box) otherBoxes |> Array.length
collisionCount <- count
count > 0

let CheckCollision (level: Level) (entityBox: Box) (otherBoxes: Box[]): Collision =
let CheckCollision (level: Level) (entity: Box) (objects: Box[]): Collision =
let mutable collisionWithObjectCount = 0
let colliders = [|
(IsOutOfBounds, Collision.OutOfBounds)
(IsCollidesBricks level, Collision.CollidesBrick)
(IsBoxCollidesOther otherBoxes, Collision.CollidesBox)
(IsOutOfBounds, lazy Collision.OutOfBounds)
(HasBrickCollision level, lazy Collision.CollidesBrick)
((fun box -> IsBoxCollidesOther objects &collisionWithObjectCount box), lazy Collision.CollidesObject collisionWithObjectCount)
|]
let isCollides = ((|>) entityBox) << fst
let isCollides = ((|>) entity) << fst
match Array.tryFind isCollides colliders with
| Some (_, reason) -> reason
| Some (_, reasonLazy) -> reasonLazy.Value
| None -> Collision.None

let IsTriggered (trigger: Trigger) (entityBox: Box)=
Expand Down
17 changes: 14 additions & 3 deletions O21.Tests/GameEngineTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -355,9 +355,20 @@ module Geometry =
|]

let isAllCollides =
(topLeft, true)
||> Array.foldBack (fun p acc ->
topLeft
|> Array.forall (fun p ->
let box = { TopLeft = p; Size = size }
acc && (CheckCollision level box1 [| box |]).IsCollidesBox)
(CheckCollision level box1 [| box |]).IsCollidesObject)

Assert.True(isAllCollides)

[<Fact>]
let ``Collision with objects counter in one tick test``(): unit =
let level = createEmptyLevel 50 50
let objectCount = 10
let entity = { TopLeft = Point(20, 20); Size = Vector(10, 10) }
let objects = entity |> Array.create objectCount

match CheckCollision level entity objects with
| Collision.CollidesObject count -> Assert.Equal(objectCount, count)
| _ -> Assert.Fail("Entity doesn't collides any object")

0 comments on commit 752c91c

Please sign in to comment.