Commit 5666b7f8 authored by Vivien Leclercq's avatar Vivien Leclercq
Browse files

Update Boid/agent/boid.go, Boid/agent/music.go, Boid/agent/predator.go,...

Update Boid/agent/boid.go, Boid/agent/music.go, Boid/agent/predator.go, Boid/flock/flock.go, Boid/game/game.go, Boid/game/level.go, Boid/game/score.go, Boid/game/graphics.go, Boid/utils/images/background.png, Boid/utils/images/bomb.png, Boid/utils/images/chevron-up.png, Boid/utils/images/poisson-1.png, Boid/utils/images/poisson-2.png, Boid/utils/images/poisson-3.png, Boid/utils/images/poisson-5.png, Boid/utils/images/poisson-8.png, Boid/utils/images/predT2.png, Boid/utils/images/predT3.png, Boid/utils/images/predT4.png, Boid/utils/images/sand2.png, Boid/utils/images/poisson-4.png, Boid/utils/constant.go, Boid/utils/lasso.go, Boid/utils/variable.go, Boid/utils/vector.go, Boid/go.mod, Boid/main.go, Boid/go.sum, Boid/worldelements/wall.go files
Deleted Boid/agent/boid/boid.go, Boid/agent/music/music.go, Boid/agent/wall/wall.go, Boid/flock/.gitkeep, Boid/utils/constant/constant.go, Boid/utils/vector/vector.go, Boid/utils/variable/variable.go files
parent 7fd6585e
package agent
import (
"math/rand"
utils "gitlab.utc.fr/projet_ia04/Boid/utils"
worldelements "gitlab.utc.fr/projet_ia04/Boid/worldelements"
)
type Boid struct {
ImageWidth int
ImageHeight int
Position utils.Vector2D
Velocity utils.Vector2D
Acceleration utils.Vector2D
Species int
Dead bool
EscapePredator float64
Marqued bool
}
//GenerateBoids fonction qui permet de générer des agents Boids
func GenerateBoids() []*Boid {
boids := make([]*Boid, utils.NumBoids)
for i := range boids {
w, h := utils.FishImage1.Size()
// Pour éviter que les agents apparaisent au dessus ou en dessous des murs de bombes:
// on les fait apparaitre horizontalement en ligne au mileu de l'écran:
middle := utils.ScreenHeight / 2
x, y := rand.Float64()*float64(utils.ScreenWidth-w), float64(middle)
min, max := -utils.MaxForce, utils.MaxForce
vx, vy := rand.Float64()*(max-min)+min, rand.Float64()*(max-min)+min
s := rand.Intn(utils.NumSpecies)
boids[i] = &Boid{
ImageWidth: w,
ImageHeight: h,
Position: utils.Vector2D{X: x, Y: y},
Velocity: utils.Vector2D{X: vx, Y: vy},
Acceleration: utils.Vector2D{X: 0, Y: 0},
Species: s,
Dead: false,
EscapePredator: 80.0,
Marqued: false,
}
}
return boids
}
//Update fonction qui permet de mettre à jour le Boid
func (boid *Boid) Update(level int, walls []*worldelements.Wall, boids []*Boid, predators []*Predator) {
if !boid.CheckEdges() {
if !boid.CheckWalls(walls) {
boid.ApplyRules(boids, predators)
}
}
boid.ApplyMovement()
// Pour éviter que les poissons réussissent à s'échapper des murs de bombes
// dans les niveaux supérieurs ou égal au niveau 4: (le dernier niveau pour le moment)
// Dès que l'on detecte qu'ils ne sont pas où ils devraient être, on les fait réapparaitre au centre
if level >= 4 && (boid.Position.Y <= 0 || boid.Position.Y >= float64(utils.ScreenHeight)) {
boid.Position.Y = float64(utils.ScreenHeight) / 2
}
}
func (boid *Boid) ApplyRules(restOfFlock []*Boid, predators []*Predator) {
if !boid.Dead {
alignSteering := utils.Vector2D{}
alignTotal := 0
cohesionSteering := utils.Vector2D{}
cohesionTotal := 0
separationSteering := utils.Vector2D{}
separationTotal := 0
istherepred := false
// check predator presence
if boid.Marqued {
if boid.Species == 3 {
goback := boid.Velocity
goback.Multiply(2.5 * 3.0)
boid.Acceleration.Add(goback)
}
if boid.Species == 4 {
goback := utils.Rotate(boid.Velocity, int(rand.Float64()*360))
goback.Multiply(2.5 * 3.0)
boid.Acceleration.Add(goback)
}
boid.Marqued = false
return
}
for _, pred := range predators {
d := boid.Position.Distance(pred.Position)
if d < boid.EscapePredator {
istherepred = true
// 180 retour espece 1
if boid.Species == 1 {
goback := boid.Velocity // on divise par 3 à la fin de la fonction
goback.Multiply(2.5 * 3.0)
boid.Acceleration.Add(goback)
}
if boid.Species == 2 {
// eclatement de la population, orientation aleatoire
goback := utils.Rotate(boid.Velocity, int(rand.Float64()*360))
goback.Multiply(2.5 * 3.0)
boid.Acceleration.Add(goback)
}
if boid.Species == 3 || boid.Species == 4 {
// Le boid alerte tous ses voisins qui partent dans une direction donnée si il n'est pas marqué
for _, other := range restOfFlock {
d := boid.Position.Distance(other.Position)
if d < utils.SeparationPerception {
other.Marqued = true
}
}
}
}
}
if !(istherepred) {
for _, other := range restOfFlock {
d := boid.Position.Distance(other.Position)
if boid != other {
if boid.Species == other.Species && d < utils.AlignPerception {
alignTotal++
alignSteering.Add(other.Velocity)
}
if boid.Species == other.Species && d < utils.CohesionPerception {
cohesionTotal++
cohesionSteering.Add(other.Position)
}
if d < utils.SeparationPerception {
separationTotal++
diff := boid.Position
diff.Subtract(other.Position)
diff.Divide(d)
separationSteering.Add(diff)
if other.Species != boid.Species {
diff.Divide(d * utils.RepulsionFactorBtwnSpecies)
separationSteering.Add(diff)
}
}
}
}
}
if separationTotal > 0 {
separationSteering.Divide(float64(separationTotal))
separationSteering.SetMagnitude(utils.MaxSpeed)
separationSteering.Subtract(boid.Velocity)
separationSteering.SetMagnitude(utils.MaxForce * 1.2)
}
if cohesionTotal > 0 {
cohesionSteering.Divide(float64(cohesionTotal))
cohesionSteering.Subtract(boid.Position)
cohesionSteering.SetMagnitude(utils.MaxSpeed)
cohesionSteering.Subtract(boid.Velocity)
cohesionSteering.SetMagnitude(utils.MaxForce * 0.9)
}
if alignTotal > 0 {
alignSteering.Divide(float64(alignTotal))
alignSteering.SetMagnitude(utils.MaxSpeed)
alignSteering.Subtract(boid.Velocity)
alignSteering.Limit(utils.MaxForce)
}
boid.Acceleration.Add(alignSteering)
boid.Acceleration.Add(cohesionSteering)
boid.Acceleration.Add(separationSteering)
boid.Acceleration.Divide(3)
}
}
func (boid *Boid) ApplyMovement() {
if !boid.Dead {
boid.Position.Add(boid.Velocity)
boid.Velocity.Add(boid.Acceleration)
boid.Velocity.Limit(utils.MaxSpeed)
boid.Acceleration.Multiply(0.0)
}
}
func (boid *Boid) CheckEdges() bool {
if boid.Position.X < 0 {
boid.Position.X = utils.ScreenWidth
} else if boid.Position.X > utils.ScreenWidth {
boid.Position.X = 0
}
return false
}
//CheckWall fonction qui permet de vérifier la présence de murs
func (boid *Boid) CheckWalls(walls []*worldelements.Wall) bool {
separationTotal := 0
separationSteering := utils.Vector2D{}
for _, wall := range walls {
d := boid.Position.Distance(wall.Position)
if d < utils.WallSeparationPerception {
separationTotal++
diff := boid.Position
diff.Subtract(wall.Position)
diff.Divide(d)
separationSteering.Add(diff)
}
}
if separationTotal > 0 {
separationSteering.Divide(float64(separationTotal))
separationSteering.SetMagnitude(utils.MaxSpeed)
separationSteering.Subtract(boid.Velocity)
separationSteering.SetMagnitude(utils.MaxForce * 1.2)
boid.Acceleration.Add(separationSteering)
return true
}
return false
}
package boid
import (
"math"
"math/rand"
wall "gitlab.utc.fr/projet_ia04/Boid/agent/wall"
constant "gitlab.utc.fr/projet_ia04/Boid/utils/constant"
variable "gitlab.utc.fr/projet_ia04/Boid/utils/variable"
vector "gitlab.utc.fr/projet_ia04/Boid/utils/vector"
)
type Vector2D = vector.Vector2D
type Boid struct {
ImageWidth int
ImageHeight int
Position Vector2D
Velocity Vector2D
Acceleration Vector2D
Species int
Dead bool
EscapePredator float64
Marqued bool
}
type Predator struct {
ImageWidth int
ImageHeight int
Position Vector2D
Velocity Vector2D
Acceleration Vector2D
Density int
Angle int
Dist int
V1 Vector2D
V2 Vector2D
R bool
}
func (boid *Boid) ApplyRules(restOfFlock []*Boid, predators []*Predator) {
if !boid.Dead {
alignSteering := Vector2D{}
alignTotal := 0
cohesionSteering := Vector2D{}
cohesionTotal := 0
separationSteering := Vector2D{}
separationTotal := 0
istherepred := false
// check predator presence
if boid.Marqued {
if boid.Species == 3 {
goback := boid.Velocity
goback.Multiply(2.5 * 3.0)
boid.Acceleration.Add(goback)
}
if boid.Species == 4 {
goback := vector.Rotate(boid.Velocity, int(rand.Float64()*360))
goback.Multiply(2.5 * 3.0)
boid.Acceleration.Add(goback)
}
boid.Marqued = false
return
}
for _, pred := range predators {
d := boid.Position.Distance(pred.Position)
if d < boid.EscapePredator {
istherepred = true
// 180 retour espece 1
if boid.Species == 1 {
goback := boid.Velocity // on divise par 3 à la fin de la fonction
goback.Multiply(2.5 * 3.0)
boid.Acceleration.Add(goback)
}
if boid.Species == 2 {
// eclatement de la population, orientation aleatoire
goback := vector.Rotate(boid.Velocity, int(rand.Float64()*360))
goback.Multiply(2.5 * 3.0)
boid.Acceleration.Add(goback)
}
if boid.Species == 3 || boid.Species == 4 {
// Le boid alerte tous ses voisins qui partent dans une direction donnée si il n'est pas marqué
for _, other := range restOfFlock {
d := boid.Position.Distance(other.Position)
if d < variable.SeparationPerception {
other.Marqued = true
}
}
}
}
}
if !(istherepred) {
for _, other := range restOfFlock {
d := boid.Position.Distance(other.Position)
if boid != other {
if boid.Species == other.Species && d < variable.AlignPerception {
alignTotal++
alignSteering.Add(other.Velocity)
}
if boid.Species == other.Species && d < variable.CohesionPerception {
cohesionTotal++
cohesionSteering.Add(other.Position)
}
if d < variable.SeparationPerception {
separationTotal++
diff := boid.Position
diff.Subtract(other.Position)
diff.Divide(d)
separationSteering.Add(diff)
if other.Species != boid.Species {
diff.Divide(d * variable.RepulsionFactorBtwnSpecies)
separationSteering.Add(diff)
}
}
}
}
}
if separationTotal > 0 {
separationSteering.Divide(float64(separationTotal))
separationSteering.SetMagnitude(variable.MaxSpeed)
separationSteering.Subtract(boid.Velocity)
separationSteering.SetMagnitude(variable.MaxForce * 1.2)
}
if cohesionTotal > 0 {
cohesionSteering.Divide(float64(cohesionTotal))
cohesionSteering.Subtract(boid.Position)
cohesionSteering.SetMagnitude(variable.MaxSpeed)
cohesionSteering.Subtract(boid.Velocity)
cohesionSteering.SetMagnitude(variable.MaxForce * 0.9)
}
if alignTotal > 0 {
alignSteering.Divide(float64(alignTotal))
alignSteering.SetMagnitude(variable.MaxSpeed)
alignSteering.Subtract(boid.Velocity)
alignSteering.Limit(variable.MaxForce)
}
boid.Acceleration.Add(alignSteering)
boid.Acceleration.Add(cohesionSteering)
boid.Acceleration.Add(separationSteering)
boid.Acceleration.Divide(3)
}
}
func (boid *Boid) ApplyMovement() {
if !boid.Dead {
boid.Position.Add(boid.Velocity)
boid.Velocity.Add(boid.Acceleration)
boid.Velocity.Limit(variable.MaxSpeed)
boid.Acceleration.Multiply(0.0)
}
}
// func (boid *Boid) CheckEdges() bool {
// separationTotal := 0
// separationSteering := Vector2D{}
// if boid.Position.X < 10 {
// separationTotal++
// Position := Vector2D{X: 0, Y: boid.Position.Y}
// d := boid.Position.Distance(Position)
// diff := boid.Position
// diff.Subtract(Position)
// diff.Divide(d)
// separationSteering.Add(diff)
// }
// if boid.Position.X > constant.ScreenWidth-10 {
// separationTotal++
// Position := Vector2D{X: constant.ScreenWidth, Y: boid.Position.Y}
// d := boid.Position.Distance(Position)
// diff := boid.Position
// diff.Subtract(Position)
// diff.Divide(d)
// separationSteering.Add(diff)
// }
// if boid.Position.Y < 10 {
// separationTotal++
// Position := Vector2D{X: boid.Position.X, Y: 0}
// d := boid.Position.Distance(Position)
// diff := boid.Position
// diff.Subtract(Position)
// diff.Divide(d)
// separationSteering.Add(diff)
// }
// if boid.Position.Y > constant.ScreenHeight-10 {
// separationTotal++
// Position := Vector2D{X: boid.Position.X, Y: constant.ScreenHeight}
// d := boid.Position.Distance(Position)
// diff := boid.Position
// diff.Subtract(Position)
// diff.Divide(d)
// separationSteering.Add(diff)
// }
// if separationTotal > 0 {
// separationSteering.Divide(float64(separationTotal))
// separationSteering.SetMagnitude(constant.MaxSpeed)
// separationSteering.Subtract(boid.Velocity)
// separationSteering.SetMagnitude(constant.MaxForce * 1.2)
// boid.Acceleration.Add(separationSteering)
// return true
// }
// return false
// }
// NO BORDER VERSION
func (boid *Boid) CheckEdges() bool {
if boid.Position.X < 0 {
boid.Position.X = constant.ScreenWidth
} else if boid.Position.X > constant.ScreenWidth {
boid.Position.X = 0
}
//if boid.Position.Y < 0 {
// boid.Position.Y = constant.ScreenHeight
//} else if boid.Position.Y > constant.ScreenHeight {
// boid.Position.Y = 0
// }
return false
}
func (boid *Boid) CheckWalls(walls []*wall.Wall) bool {
separationTotal := 0
separationSteering := Vector2D{}
for _, wall := range walls {
d := boid.Position.Distance(wall.Position)
if d < constant.WallSeparationPerception {
separationTotal++
diff := boid.Position
diff.Subtract(wall.Position)
diff.Divide(d)
separationSteering.Add(diff)
}
}
if separationTotal > 0 {
separationSteering.Divide(float64(separationTotal))
separationSteering.SetMagnitude(variable.MaxSpeed)
separationSteering.Subtract(boid.Velocity)
separationSteering.SetMagnitude(variable.MaxForce * 1.2)
boid.Acceleration.Add(separationSteering)
return true
}
return false
}
// ----------------------------------------------
// ---------------------------------- PREDATOR -------------------------- //
// ----------------------------------------------
func (preda *Predator) Vision() []Vector2D {
x := preda.Position.X
y := preda.Position.Y
vx := preda.Velocity.X
vy := preda.Velocity.Y
//calculate angle between vect Velocity and x-axis
angR := math.Atan2(vy, vx)
angV := int(angR * 180 / math.Pi)
// Calulate upper and lower angle
angU := angV - preda.Angle
angL := angV + preda.Angle
// Calculate new point
l1x := x + float64(preda.Dist)*math.Cos(vector.AngleToRadians(angU))
l1y := y + float64(preda.Dist)*math.Sin(vector.AngleToRadians(angU))
l2x := x + float64(preda.Dist)*math.Cos(vector.AngleToRadians(angL))
l2y := y + float64(preda.Dist)*math.Sin(vector.AngleToRadians(angL))
p1 := Vector2D{X: l1x, Y: l1y}
p2 := Vector2D{X: l2x, Y: l2y}
mapP := make([]Vector2D, 2)
mapP[0] = p1
mapP[1] = p2
return mapP
}
func (preda *Predator) ApplyRules(restOfFlock []*Boid) {
//preda.V1 = vPoint[0]
//preda.V2 = vPoint[1]
var dens int
var newP Predator
var new bool
var densMax = 0
var densMax2 = 0
var proie1 *Boid
var proie2 *Boid
var vPoint2 []Vector2D
//Tuer les boid se situant à une distance inférieure à 10
for _, Boid := range restOfFlock {
if (preda.Position.Distance(Boid.Position)) < 10 {
Boid.Dead = true
}
}
//Calcule de la postion des points correspondant au champ de vision
vPoint := preda.Vision()
new = false
//Calcule nouveau point si 1 des premiers se situe à l'exterieur de la carte
if (vPoint[0].X > constant.ScreenWidth || vPoint[0].X < 0) || (vPoint[0].Y > constant.ScreenHeight || vPoint[0].Y < 0) || (vPoint[1].X > constant.ScreenWidth || vPoint[1].X < 0) || (vPoint[1].Y > constant.ScreenHeight || vPoint[1].Y < 0) {
new = true
//on crée également un objet predateur "fantome" (situer à X - ScreenWidth et Y + ScreenHeight) pour gérer la detection des boids de l'autre coté de la carte
newP = *preda
if vPoint[0].X > constant.ScreenWidth {
newP.Position.X = preda.Position.X - constant.ScreenWidth
} else if vPoint[0].X < 0 {
newP.Position.X = preda.Position.X + constant.ScreenWidth
}
//if vPoint[0].Y > constant.ScreenHeight {
//newP.Position.Y = preda.Position.Y - constant.ScreenHeight
//} else if vPoint[0].Y < 0 {
// newP.Position.Y = preda.Position.Y + constant.ScreenHeight
//}
if vPoint[1].X > constant.ScreenWidth {
newP.Position.X = preda.Position.X - constant.ScreenWidth
} else if vPoint[1].X < 0 {
newP.Position.X = preda.Position.X + constant.ScreenWidth
}
//if vPoint[1].Y > constant.ScreenHeight {
// newP.Position.Y = preda.Position.Y - constant.ScreenHeight
//} else if vPoint[1].Y < 0 {
// newP.Position.Y = preda.Position.Y + constant.ScreenHeight
//}
}
preda.V1 = vPoint[0]
preda.V2 = vPoint[1]
if new {
vPoint2 = newP.Vision()
if vPoint[1].X > constant.ScreenWidth || vPoint[1].X < 0 {
preda.V2 = vPoint2[1]
}
if vPoint[0].X > constant.ScreenWidth || vPoint[0].X < 0 {
preda.V1 = vPoint2[0]
}
}
//Pour chaque boid
for _, Boid := range restOfFlock {
if !Boid.Dead {
dens = 0
b := vector.PointInTriangle(Boid.Position, preda.Position, vPoint[0], vPoint[1])
b2 := false
//Si un point de vision dépasse les limites de la carte
if new {
b2 = vector.PointInTriangle(Boid.Position, newP.Position, vPoint2[0], vPoint2[1])
}
//Si il est dans le champ de vision du prédateur
if b {
//On calcule le nombre de voisin se situant à moins de 30 pixels de distance
for _, other := range restOfFlock {
if (Boid.Position.Distance(other.Position)) < 30 && !other.Dead {
dens++
}
}
}
if dens > densMax {
densMax = dens
proie1 = Boid
}
dens = 0
//Si un point de vision dépasse les limites de la carte
if b2 {
//print(1)
for _, other := range restOfFlock {
if (Boid.Position.Distance(other.Position)) < 30 && !other.Dead {
dens++
}
}
}
if dens > densMax2 {
densMax2 = dens
proie2 = Boid
}
}
}
//Si une "zone" à une densité supérieur à preda.Density
if densMax >= densMax2 && densMax > preda.Density {
//On modifie le vecteur vitesse du prédateur pour le faire diriger dans la zone
Vit := vector.Vector2D{X: proie1.Position.X - preda.Position.X, Y: proie1.Position.Y - preda.Position.Y}
Vit.Normalize()
Vit.X = Vit.X * 10
Vit.Y = Vit.Y * 10
preda.Velocity = Vit