func fireDoLine(c *cmwc.Cmwc, pos linear.Vec2, angle, stored float64, speed int, level *game.Level) fireExplosion { rng := rand.New(c) ray := (linear.Vec2{1, 0}) // ray.Scale(math.Abs(rng.NormFloat64()/10) + 50) scale := (stored/5 + 50) * (1 + rng.Float64()*(0.2+stored/2000)) ray = ray.Rotate(angle).Rotate(rng.NormFloat64() * (0.2 + stored/7500)).Scale(scale) seg := linear.Seg2{pos, pos.Add(ray)} base.DoOrdered(level.Room.Walls, func(a, b string) bool { return a < b }, func(_ string, poly linear.Poly) { for i := range poly { if seg.DoesIsect(poly.Seg(i)) { isect := seg.Isect(poly.Seg(i)) seg.Q = isect } } }) p1 := rng.Intn(speed) p2 := rng.Intn(speed) p3 := rng.Intn(speed) return fireExplosion{ Pos: seg.Q, Radius: rng.Float64()*40 + 30, Timer: 0, Start: 1*speed + p1, Peak: 4*speed + p1 + p2, End: 5*speed + p1 + p2 + p3, } }
func (pd *PathingData) Dir(src, dst linear.Vec2) linear.Vec2 { x := int(src.X / pathingDataGrid) y := int(src.Y / pathingDataGrid) x2 := int(dst.X / pathingDataGrid) y2 := int(dst.Y / pathingDataGrid) if x < 0 || y < 0 || x >= len(pd.dstData) || y >= len(pd.dstData[x]) { return linear.Vec2{0, 0} } if x2 < 0 || y2 < 0 || x2 >= len(pd.dstData) || y2 >= len(pd.dstData[x2]) { return linear.Vec2{0, 0} } dstData := &pd.dstData[x2][y2] dstData.RLock() defer dstData.RUnlock() if !dstData.complete { dstData.once.Do(func() { base.Log().Printf("Eval: %2.2v %2.2v", src, dst) go func() { pd.finishDirectPaths.Wait() dstData.Lock() defer dstData.Unlock() pd.findAllPaths(x2, y2) dstData.complete = true }() }) return dst.Sub(src).Norm() } cell := pd.dirs[x2][y2][x][y] if !cell.direct { return (linear.Vec2{1, 0}).Rotate(cell.angle) } return dst.Sub(src).Norm() }
func (p *pullProcess) Think(g *game.Game) { _player := g.GetEnt(p.Player_id) player := _player.(*game.Player) base_force := p.Force * p.supplied / p.required for _, _target := range g.Ents { target, ok := _target.(*game.Player) if !ok || target == player { continue } target_pos := linear.Vec2{target.X, target.Y} ray := target_pos.Sub(player.Pos()) target_angle := ray.Angle() - player.Angle for target_angle < 0 { target_angle += math.Pi * 2 } for target_angle > math.Pi*2 { target_angle -= math.Pi * 2 } if target_angle > p.Angle/2 && target_angle < math.Pi*2-p.Angle/2 { continue } ray = player.Pos().Sub(target.Pos()) // dist := ray.Mag() ray = ray.Norm() force := base_force // / math.Pow(dist, p.Angle/(2*math.Pi)) target.ApplyForce(ray.Scale(-force)) player.ApplyForce(ray.Scale(force)) } }
// Queries the input system for the direction that this controller is moving in func getControllerDirection(controller gin.DeviceId) linear.Vec2 { v := linear.Vec2{ axisControl(control.right.CurPressAmt()) - axisControl(control.left.CurPressAmt()), axisControl(control.down.CurPressAmt()) - axisControl(control.up.CurPressAmt()), } if v.Mag2() > 1 { v = v.Norm() } return v }
func (g *Game) RenderLocalEditor(region g2.Region) { g.editor.Lock() defer g.editor.Unlock() g.editor.region = region g.editor.camera.regionDims = linear.Vec2{float64(region.Dims.Dx), float64(region.Dims.Dy)} levelDims := linear.Vec2{float64(g.Level.Room.Dx), float64(g.Level.Room.Dy)} g.editor.camera.StandardRegion(levelDims.Scale(0.5), levelDims) g.editor.camera.approachTarget() gl.MatrixMode(gl.PROJECTION) gl.PushMatrix() gl.LoadIdentity() defer gl.PopMatrix() gl.PushAttrib(gl.VIEWPORT_BIT) gl.Viewport(gl.Int(region.X), gl.Int(region.Y), gl.Sizei(region.Dx), gl.Sizei(region.Dy)) defer gl.PopAttrib() current := &g.editor.camera.current gl.Ortho( gl.Double(current.mid.X-current.dims.X/2), gl.Double(current.mid.X+current.dims.X/2), gl.Double(current.mid.Y+current.dims.Y/2), gl.Double(current.mid.Y-current.dims.Y/2), gl.Double(1000), gl.Double(-1000), ) defer func() { gl.MatrixMode(gl.PROJECTION) gl.PopMatrix() gl.MatrixMode(gl.MODELVIEW) }() gl.MatrixMode(gl.MODELVIEW) gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) g.renderWalls() g.renderEdges() g.renderBases() g.renderEntsAndAbilities() g.renderProcesses() g.editor.renderPathing(&g.Level.Room, g.local.pathingData) switch g.editor.action { case editorActionNone: case editorActionPlaceBlock: g.editor.renderPlaceBlock(g) default: base.Error().Printf("Unexpected editorAction: %v", g.editor.action) } }
func (editor *editorData) getPoly(g *Game) linear.Poly { pos := editor.cursorPosInGameCoords(&g.Level.Room) var offset linear.Vec2 offset.X = pos.X - editor.placeBlock.offset.X offset.X = math.Floor(offset.X/editor.placeBlock.grid+0.5) * editor.placeBlock.grid offset.Y = pos.Y - editor.placeBlock.offset.Y offset.Y = math.Floor(offset.Y/editor.placeBlock.grid+0.5) * editor.placeBlock.grid block := make(linear.Poly, len(editor.placeBlock.block)) for i := range editor.placeBlock.block { block[i] = editor.placeBlock.block[i].Add(offset) } return block }
func ComplexOperationsSpec(c gospec.Context) { c.Specify("Vec2.DistToLine() works.", func() { centers := []linear.Vec2{ linear.Vec2{10, 12}, linear.Vec2{1, -9}, linear.Vec2{-100, -42}, linear.Vec2{0, 1232}, } radiuses := []float64{3, 10.232, 435, 1} thetas := []float64{0.001, 0.1, 1, 1.01, 0.034241, 0.789, 90, 179, 180} angles := []float64{1.01, 1.0, 1.11111, 930142} for _, center := range centers { for _, radius := range radiuses { for _, angle := range angles { for _, theta := range thetas { a := linear.Vec2{math.Cos(angle), math.Sin(angle)} b := linear.Vec2{math.Cos(angle + theta), math.Sin(angle + theta)} seg := linear.Seg2{a.Scale(radius).Add(center), b.Scale(radius).Add(center)} dist := center.DistToLine(seg) real_dist := radius * math.Cos(theta/2) if real_dist < 0 { real_dist = -real_dist } c.Expect(dist, IsWithin(1e-9), real_dist) } } } } }) }
func (g *Game) AddCreeps(pos linear.Vec2, count, side int, params map[string]interface{}) { if side < 0 || side >= len(g.Level.Room.SideData) { base.Error().Fatalf("Got side %d, but this level only supports sides from 0 to %d.", side, len(g.Level.Room.SideData)-1) return } for i := 0; i < count; i++ { var c CreepEnt c.StatsInst = stats.Make(stats.Base{ Health: 100, Mass: 250, Acc: 50.0, Rate: 0.0, Size: 8, Vision: 400, }) // Evenly space the players on a circle around the starting position. randAngle := rand.New(g.Rng).Float64() * math.Pi rot := (linear.Vec2{15, 0}).Rotate(randAngle + float64(i)*2*3.1415926535/float64(count)) c.Position = pos.Add(rot) c.Side_ = side c.Gid = g.NextGid() c.Abilities_ = append( c.Abilities_, ability_makers["asplode"](map[string]float64{"startRadius": 40, "endRadius": 70, "durationThinks": 50, "dps": 5})) // if playerData.gid[0:2] == "Ai" { // c.BindAi("simple", g.local.Engine) // } g.AddEnt(&c) c.BindAi("creep", g.local.Engine) for name, value := range params { c.ai.SetParam(name, value) } } }
func (tm *ThunderMenu) Draw(region Region, style StyleStack) { // Set clip planes gl.PushAttrib(gl.TRANSFORM_BIT) defer gl.PopAttrib() var eqs [4][4]gl.Double eqs[0][0], eqs[0][1], eqs[0][2], eqs[0][3] = 1, 0, 0, -gl.Double(region.X) eqs[1][0], eqs[1][1], eqs[1][2], eqs[1][3] = -1, 0, 0, gl.Double(region.X+region.Dx) eqs[2][0], eqs[2][1], eqs[2][2], eqs[2][3] = 0, 1, 0, -gl.Double(region.Y) eqs[3][0], eqs[3][1], eqs[3][2], eqs[3][3] = 0, -1, 0, gl.Double(region.Y+region.Dy) gl.Enable(gl.CLIP_PLANE0) gl.Enable(gl.CLIP_PLANE1) gl.Enable(gl.CLIP_PLANE2) gl.Enable(gl.CLIP_PLANE3) gl.ClipPlane(gl.CLIP_PLANE0, &eqs[0][0]) gl.ClipPlane(gl.CLIP_PLANE1, &eqs[1][0]) gl.ClipPlane(gl.CLIP_PLANE2, &eqs[2][0]) gl.ClipPlane(gl.CLIP_PLANE3, &eqs[3][0]) var start, end int if tm.delta <= 0 { start = tm.current + int(math.Floor(tm.delta)) end = tm.current region.X += int(float64(region.Dx) * (float64(start-tm.current) - tm.delta)) } else { start = tm.current end = tm.current + int(math.Ceil(tm.delta)) region.X += int(float64(region.Dx) * (float64(end-tm.current) - tm.delta - math.Floor(tm.delta) - 1)) } var offset linear.Vec2 offset.X = (float64(tm.current) + tm.delta) * float64(region.Dx) for i := start; i <= end; i++ { style.PushStyle(map[string]interface{}{"offset": offset}) tm.Subs[tm.menuStack[i]].Draw(region, style) style.Pop() region.X += region.Dx } }
func (editor *editorData) cursorPosInGameCoords(room *Room) linear.Vec2 { x, y := editor.sys.GetCursorPos() pos := linear.Vec2{float64(x), float64(y)} regionPos := linear.Vec2{float64(editor.region.Pos.X), float64(editor.region.Pos.Y)} pos = pos.Sub(regionPos) pos = pos.Scale(float64(room.Dx) / float64(editor.region.Dims.Dx)) cameraOffset := linear.Vec2{ editor.camera.current.dims.X/2 - editor.camera.current.mid.X, editor.camera.current.dims.Y/2 - editor.camera.current.mid.Y, } pos = pos.Sub(cameraOffset) return pos }
func (pd *PathingData) findAllDirectPaths(dstx, dsty int, room *Room) { defer pd.finishDirectPaths.Done() dst := linear.Vec2{(float64(dstx) + 0.5) * pathingDataGrid, (float64(dsty) + 0.5) * pathingDataGrid} for x := range pd.dirs[dstx][dsty] { for y := range pd.dirs[dstx][dsty][x] { src := linear.Vec2{(float64(x) + 0.5) * pathingDataGrid, (float64(y) + 0.5) * pathingDataGrid} if dstx == 1 && dsty == 4 { } if room.ExistsLos(src, dst) { if dstx == 1 && dsty == 4 { } pd.conns[dstx][dsty] = append(pd.conns[dstx][dsty], pathingConnection{ x: x, y: y, dist: dst.Sub(src).Mag(), }) data := &pd.dirs[dstx][dsty][x][y] data.angle = src.Sub(dst).Angle() data.direct = true // data.filled = true } } } }
func BasicPropertiesSpec(c gospec.Context) { a := linear.Vec2{3, 4} b := linear.Vec2{5, 6} c.Specify("Check that (cross a) dot a == 0.", func() { c.Expect(a.Cross().Dot(a), Equals, 0.0) }) c.Specify("Check that a normalize vector's magnitude is 1.", func() { c.Expect(a.Norm().Mag(), IsWithin(1e-9), 1.0) }) c.Specify("Check that v.Mag2() == v.Mag()*v.Mag()", func() { c.Expect(a.Mag2(), IsWithin(1e-9), a.Mag()*a.Mag()) }) c.Specify("Check that a scaled vector's magnitude is appropriately scaled.", func() { c.Expect(a.Scale(3.5).Mag(), IsWithin(1e-9), a.Mag()*3.5) }) c.Specify("Check that a-(a-b) == b.", func() { VecExpect(c, a.Sub(a.Sub(b)), IsWithin(1e-9), b) }) }
func (p *Player) ApplyForce(f linear.Vec2) { dv := f.Scale(1 / p.Mass()) p.Vx += dv.X p.Vy += dv.Y }
func BasicOperationsSpec(c gospec.Context) { a := linear.Vec2{3, 4} b := linear.Vec2{5, 6} c.Specify("Make sure adding vectors works.", func() { VecExpect(c, a.Add(b), Equals, linear.Vec2{8, 10}) }) c.Specify("Make sure subtracting vectors works.", func() { VecExpect(c, a.Sub(b), Equals, linear.Vec2{-2, -2}) }) c.Specify("Make sure dotting vectors works.", func() { c.Expect(a.Dot(b), IsWithin(1e-9), 39.0) }) c.Specify("Make sure crossing vectors works.", func() { VecExpect(c, a.Cross(), Equals, linear.Vec2{-4, 3}) }) c.Specify("Make sure taking the magnitude of vectors works.", func() { c.Expect(a.Mag(), IsWithin(1e-9), 5.0) c.Expect(a.Mag2(), IsWithin(1e-9), 25.0) }) c.Specify("Make sure scaling vectors works.", func() { VecExpect(c, a.Scale(3), Equals, linear.Vec2{9, 12}) }) }
func (camera *cameraInfo) doInvadersFocusRegion(g *Game, side int) { min := linear.Vec2{1e9, 1e9} max := linear.Vec2{-1e9, -1e9} hits := 0 for _, ent := range g.temp.AllEnts { if ent.Side() != side { continue } if player, ok := ent.(*PlayerEnt); ok { hits++ pos := player.Pos() if pos.X < min.X { min.X = pos.X } if pos.Y < min.Y { min.Y = pos.Y } if pos.X > max.X { max.X = pos.X } if pos.Y > max.Y { max.Y = pos.Y } } } if hits == 0 { min.X = 0 min.Y = 0 max.X = float64(g.Levels[GidInvadersStart].Room.Dx) max.Y = float64(g.Levels[GidInvadersStart].Room.Dy) } else { min.X -= stats.LosPlayerHorizon + 50 min.Y -= stats.LosPlayerHorizon + 50 if min.X < 0 { min.X = 0 } if min.Y < 0 { min.Y = 0 } max.X += stats.LosPlayerHorizon + 50 max.Y += stats.LosPlayerHorizon + 50 if max.X > float64(g.Levels[GidInvadersStart].Room.Dx) { max.X = float64(g.Levels[GidInvadersStart].Room.Dx) } if max.Y > float64(g.Levels[GidInvadersStart].Room.Dy) { max.Y = float64(g.Levels[GidInvadersStart].Room.Dy) } } mid := min.Add(max).Scale(0.5) dims := max.Sub(min) if dims.X/dims.Y < camera.regionDims.X/camera.regionDims.Y { dims.X = dims.Y * camera.regionDims.X / camera.regionDims.Y } else { dims.Y = dims.X * camera.regionDims.Y / camera.regionDims.X } camera.target.dims = dims camera.target.mid = mid if camera.current.mid.X == 0 && camera.current.mid.Y == 0 { // On the very first frame the current midpoint will be (0,0), which should // never happen after the game begins. In this one case we'll immediately // set current to target so we don't start off by approaching it from the // origin. camera.current = camera.target } else { // speed is in (0, 1), the higher it is, the faster current approaches target. speed := 0.1 camera.current.dims = camera.current.dims.Scale(1 - speed).Add(camera.target.dims.Scale(speed)) camera.current.mid = camera.current.mid.Scale(1 - speed).Add(camera.target.mid.Scale(speed)) } }
func (l *LocalData) thinkAbility(g *Game, abs *personalAbilities, gid Gid) { if abs.activeAbility == nil { return } var mouse linear.Vec2 if l.mode == LocalModeArchitect { mx, my := l.sys.GetCursorPos() mouse.X = float64(mx) mouse.Y = float64(my) mouse = mouse.Sub(l.architect.camera.regionPos) mouse.X /= l.architect.camera.regionDims.X mouse.Y /= l.architect.camera.regionDims.Y mouse.X *= l.architect.camera.current.dims.X mouse.Y *= l.architect.camera.current.dims.Y mouse = mouse.Sub(l.architect.camera.current.dims.Scale(0.5)) mouse = mouse.Add(l.architect.camera.current.mid) } events, die := abs.activeAbility.Think(gid, g, mouse) for _, event := range events { l.engine.ApplyEvent(event) } if die { base.Log().Printf("Deactivate on die") more_events := abs.activeAbility.Deactivate(gid) abs.activeAbility = nil for _, event := range more_events { l.engine.ApplyEvent(event) } } }
func (camera *cameraInfo) FocusRegion(g *Game, side int) { min := linear.Vec2{1e9, 1e9} max := linear.Vec2{-1e9, -1e9} player := g.Ents[g.local.Gid] if player == nil { min.X = 0 min.Y = 0 max.X = float64(g.Level.Room.Dx) max.Y = float64(g.Level.Room.Dy) } else { min.X = player.Pos().X - player.Stats().Vision() min.Y = player.Pos().Y - player.Stats().Vision() if min.X < 0 { min.X = 0 } if min.Y < 0 { min.Y = 0 } max.X = player.Pos().X + player.Stats().Vision() max.Y = player.Pos().Y + player.Stats().Vision() if max.X > float64(g.Level.Room.Dx) { max.X = float64(g.Level.Room.Dx) } if max.Y > float64(g.Level.Room.Dy) { max.Y = float64(g.Level.Room.Dy) } } mid := min.Add(max).Scale(0.5) dims := max.Sub(min) if dims.X/dims.Y < camera.regionDims.X/camera.regionDims.Y { dims.X = dims.Y * camera.regionDims.X / camera.regionDims.Y } else { dims.Y = dims.X * camera.regionDims.Y / camera.regionDims.X } camera.target.dims = dims camera.target.mid = mid camera.approachTarget() }
func (b *BaseEnt) ApplyForce(f linear.Vec2) { b.Velocity = b.Velocity.Add(f.Scale(1 / b.Mass())) }