diff --git a/game.go b/game.go index ba3b7ec..bac71fb 100644 --- a/game.go +++ b/game.go @@ -154,7 +154,7 @@ func (g *game) run() { p.scan(g.players) p.nudge(g) if p.Robot.FireAt != nil { - proj := p.fire(g.projectiles) + proj := p.fire(g.projectiles, g.turn) if proj != nil { g.projectiles[proj] = true } diff --git a/main.go b/main.go index 06a3789..1c4fbb7 100644 --- a/main.go +++ b/main.go @@ -12,7 +12,7 @@ import ( ) var addr = flag.String("addr", ":8666", "http service address") -var tick = flag.Int("tick", 33, "") +var tick = flag.Int("tick", 60, "") var verbose = flag.Bool("verbose", false, "") var width = flag.Float64("width", 800, "width of field") var height = flag.Float64("height", 550, "height of field") diff --git a/player.go b/player.go index dc43e26..bd58f6d 100644 --- a/player.go +++ b/player.go @@ -94,43 +94,49 @@ func (p *player) nudge(g *game) { if current_heading.Mag() == 0 { // We may have been stopped before this and had no heading current_heading = p.Robot.MoveTo.Sub(p.Robot.Position).Normalize() + log.Printf("Heading WAS zero, is now %v", current_heading) } // Where do we WANT to be heading? new_heading := p.Robot.MoveTo.Sub(p.Robot.Position).Normalize() - // Is our direction change too much? Hard coding to 5 degrees/s for now - angle := v.Angle(current_heading, new_heading) * v.Rad2deg - dir := 1.0 - if angle < 0 { - dir = -1.0 - } + if new_heading.Mag() > 0 { + // Is our direction change too much? Hard coding to 5 degrees/s for now + angle := v.Angle(current_heading, new_heading) * v.Rad2deg - // Max turn radius in this case is 100 degrees per second - if math.Abs(angle) > (100 * delta) { - // New heading should be a little less, take current heading and - // rotate by the max turn radius per frame. - rot := (100 * delta) * v.Deg2rad + dir := 1.0 + if angle < 0 { + dir = -1.0 + } - new_heading = current_heading.Rotate(rot * dir) - } + // Max turn radius in this case is in degrees per second + if math.Abs(angle) > (float64(p.Robot.Stats.TurnSpeed) * delta) { + // New heading should be a little less, take current heading and + // rotate by the max turn radius per frame. + rot := (float64(p.Robot.Stats.TurnSpeed) * delta) * v.Deg2rad - move_vector := new_heading.Scale(p.Robot.Speed * delta) - collision, _ := p.checkCollisions(g, move_vector) - if collision { - // p.Robot.Position = intersection_point - p.Robot.Speed = 0 - p.Robot.MoveTo = &p.Robot.Position - p.Robot.Health -= 5 - p.Robot.Heading = v.Vector2d{X: 0, Y: 0} - } else { - p.Robot.Position = p.Robot.Position.Add(move_vector) - if new_heading.Mag() > 0 { - p.Robot.Heading = new_heading + new_heading = current_heading.Rotate(rot * dir) + } + + move_vector := new_heading.Scale(p.Robot.Speed * delta) + collision, _ := p.checkCollisions(g, move_vector) + if collision { + // p.Robot.Position = intersection_point + p.Robot.Health -= int(p.Robot.Speed / 10.0) + p.Robot.MoveTo = &p.Robot.Position + p.Robot.Speed = 0 + p.Robot.Heading = v.Vector2d{X: 0, Y: 0} } else { - log.Printf("Zero Heading %v", new_heading) + p.Robot.Position = p.Robot.Position.Add(move_vector) + if new_heading.Mag() > 0 { + p.Robot.Heading = new_heading + // log.Printf("%v %v %v", new_heading, current_heading, angle) + } else { + log.Printf("Zero Heading %v", new_heading) + } } } + } func (p *player) scan(players map[*player]bool) { @@ -152,22 +158,22 @@ func (p *player) scan(players map[*player]bool) { } } -func (p *player) fire(projectiles map[*Projectile]bool) *Projectile { - // XXX: is this to prevent us from having multiple projectiles from the - // same bot? - for proj := range projectiles { - if proj.Id == p.Robot.Id { - return nil - } +func (p *player) fire(projectiles map[*Projectile]bool, turn int) *Projectile { + // Throttle the fire rate + time_since_fired := (float64(turn) * (delta * 1000)) - (float64(p.Robot.LastFired) * (delta * 1000)) + if time_since_fired < float64(p.Robot.Stats.FireRate) { + return nil } + p.Robot.LastFired = turn + return &Projectile{ Id: p.Robot.Id, Position: p.Robot.Position, MoveTo: *p.Robot.FireAt, Damage: 10, Radius: p.Robot.Stats.WeaponRadius, - Speed: float64(p.Robot.Stats.Speed * 2), + Speed: float64(p.Robot.Stats.Speed * 3), } } diff --git a/protocol.go b/protocol.go index 4e531ef..197a343 100644 --- a/protocol.go +++ b/protocol.go @@ -40,8 +40,8 @@ func (c *ClientID) Valid() (bool, string) { } type ClientConfig struct { - ID string `json:"id"` - Stats Stats `json:"stats"` + ID string `json:"id"` + Stats StatsRequest `json:"stats"` } type BoardSize struct { @@ -164,7 +164,7 @@ func addPlayer(ws *websocket.Conn) { p := &player{ Robot: Robot{ - Stats: conf.Stats, + Stats: DeriveStats(conf.Stats), Id: player_id, Name: clientid.Name, Health: conf.Stats.Hp, diff --git a/robot.go b/robot.go index a9173c8..173c89a 100644 --- a/robot.go +++ b/robot.go @@ -16,6 +16,7 @@ type Robot struct { MoveTo *v.Point2d `json:"move_to,omitempty"` FireAt *v.Point2d `json:"fire_at,omitempty"` Scanners []Scanner `json:"scanners"` + LastFired int `json:"last_fired"` } type RobotSorter struct { @@ -40,11 +41,62 @@ type Stats struct { Acceleration float64 `json:"acceleration"` WeaponRadius int `json:"weapon_radius"` ScannerRadius int `json:"scanner_radius"` + TurnSpeed int `json:"turn_speed"` + FireRate int `json:"fire_rate"` } -func (s Stats) Valid() bool { - total := int(s.Speed) + s.Hp + s.WeaponRadius + s.ScannerRadius - if total > 500 { +// We request stats using an integer between 1 and 100, the +// integer values map to sensible min-max ranges +type StatsRequest struct { + Hp int `json:"hp"` + Speed int `json:"speed"` + Acceleration int `json:"acceleration"` + WeaponRadius int `json:"weapon_radius"` + ScannerRadius int `json:"scanner_radius"` + TurnSpeed int `json:"turn_speed"` + FireRate int `json:"fire_rate"` +} + +func DeriveStats(request StatsRequest) Stats { + s := Stats{} + + // Conversion Tables + hp_min := 20.0 + hp_max := 200.0 + s.Hp = int(((float64(request.Hp) / 100.0) * (hp_max - hp_min)) + hp_min) + + speed_min := 40.0 + speed_max := 200.0 + s.Speed = ((float64(request.Speed) / 100.0) * (speed_max - speed_min)) + speed_min + + accel_min := 20.0 + accel_max := 200.0 + s.Acceleration = ((float64(request.Acceleration) / 100.0) * (accel_max - accel_min)) + accel_min + + wep_rad_min := 5.0 + wep_rad_max := 60.0 + s.WeaponRadius = int(((float64(request.WeaponRadius) / 100.0) * (wep_rad_max - wep_rad_min)) + wep_rad_min) + + scan_rad_min := 100.0 + scan_rad_max := 400.0 + s.ScannerRadius = int(((float64(request.ScannerRadius) / 100.0) * (scan_rad_max - scan_rad_min)) + scan_rad_min) + + turn_spd_min := 30.0 + turn_spd_max := 300.0 + s.TurnSpeed = int(((float64(request.TurnSpeed) / 100.0) * (turn_spd_max - turn_spd_min)) + turn_spd_min) + + fire_rate_min := 10.0 + fire_rate_max := 2000.0 + s.FireRate = int(fire_rate_max+300.0) - int(((float64(request.FireRate)/100.0)*(fire_rate_max-fire_rate_min))+fire_rate_min) + + return s +} + +func (s StatsRequest) Valid() bool { + total := (s.Speed + s.Hp + s.WeaponRadius + + s.ScannerRadius + s.Acceleration + s.TurnSpeed + s.FireRate) + + if total > 350 { return false } return true