Skip to content

Commit

Permalink
Merge pull request #83 from oakmound/feature/radardemo
Browse files Browse the repository at this point in the history
Feature/radardemo
  • Loading branch information
200sc authored Mar 2, 2019
2 parents 6f40e6c + 5ffe65a commit 82938d2
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 0 deletions.
29 changes: 29 additions & 0 deletions entities/x/move/topdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package move

import (
"github.com/oakmound/oak"
"github.com/oakmound/oak/alg/floatgeom"
"github.com/oakmound/oak/key"
"github.com/oakmound/oak/physics"
)
Expand Down Expand Up @@ -39,3 +40,31 @@ func TopDown(mvr Mover, up, down, left, right string) {
mvr.GetRenderable().SetPos(vec.X(), vec.Y())
mvr.GetSpace().Update(vec.X(), vec.Y(), 16, 16)
}

// CenterScreenOn will cause the screen to center on the given mover, obeying
// viewport limits if they have been set previously
func CenterScreenOn(mvr Mover) {
vec := mvr.Vec()
oak.SetScreen(
int(vec.X())-oak.ScreenWidth/2,
int(vec.Y())-oak.ScreenHeight/2,
)
}

// Limit restricts the movement of the mover to stay within a given rectangle
func Limit(mvr Mover, rect floatgeom.Rect2) {
vec := mvr.Vec()
w, h := mvr.GetRenderable().GetDims()
wf := float64(w)
hf := float64(h)
if vec.X() < rect.Min.X() {
vec.SetX(0)
} else if vec.X() > rect.Max.X()-wf {
vec.SetX(rect.Max.X() - wf)
}
if vec.Y() < rect.Min.Y() {
vec.SetY(0)
} else if vec.Y() > rect.Max.Y()-hf {
vec.SetY(rect.Max.Y() - hf)
}
}
File renamed without changes.
118 changes: 118 additions & 0 deletions examples/radar-demo/core.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package main

import (
"image/color"
"math"
"math/rand"

"github.com/oakmound/oak/alg/floatgeom"

"github.com/oakmound/oak"
"github.com/oakmound/oak/entities"
"github.com/oakmound/oak/entities/x/move"
"github.com/oakmound/oak/event"
"github.com/oakmound/oak/examples/radar-demo/radar"
"github.com/oakmound/oak/physics"
"github.com/oakmound/oak/render"
"github.com/oakmound/oak/scene"
)

const (
xLimit = 1000
yLimit = 1000
)

// This example demonstrates making a basic radar or other custom renderable
// type. The radar here acts as a UI element, staying on screen, and follows
// around a player character.

func main() {
oak.Add("demo", func(string, interface{}) {
char := entities.NewMoving(200, 200, 50, 50, render.NewColorBox(50, 50, color.RGBA{125, 125, 0, 255}), nil, 0, 1)
char.Speed = physics.NewVector(3, 3)

oak.SetViewportBounds(0, 0, xLimit, yLimit)
moveRect := floatgeom.NewRect2(0, 0, xLimit, yLimit)

char.Bind(func(int, interface{}) int {
move.WASD(char)
move.Limit(char, moveRect)
move.CenterScreenOn(char)
return 0
}, "EnterFrame")
render.Draw(char.R, 1, 2)

// Create the Radar
center := radar.Point{X: char.Xp(), Y: char.Yp()}
points := make(map[radar.Point]color.Color)
w := 100
h := 100
r := radar.NewRadar(w, h, points, center, 10)
r.SetPos(float64(oak.ScreenWidth-w), 0)

for i := 0; i < 5; i++ {
x, y := rand.Float64()*400, rand.Float64()*400
enemy := NewEnemyOnRadar(x, y)
enemy.CID.Bind(standardEnemyMove, "EnterFrame")
render.Draw(enemy.R, 1, 1)
r.AddPoint(radar.Point{X: enemy.Xp(), Y: enemy.Yp()}, color.RGBA{255, 255, 0, 255})
}

render.Draw(r, 2)

for x := 0; x < xLimit; x += 64 {
for y := 0; y < yLimit; y += 64 {
r := uint8(rand.Intn(120))
b := uint8(rand.Intn(120))
cb := render.NewColorBox(64, 64, color.RGBA{r, 0, b, 255})
cb.SetPos(float64(x), float64(y))
render.Draw(cb, 0)
}
}

}, func() bool {
return true
}, scene.GoTo("demo"))

render.SetDrawStack(
render.NewCompositeR(),
render.NewHeap(false),
render.NewHeap(true),
render.NewDrawFPS(),
)
oak.Init("demo")
}

type EnemyOnRadar struct {
*entities.Moving
}

func (eor *EnemyOnRadar) Init() event.CID {
return event.NextID(eor)
}
func NewEnemyOnRadar(x, y float64) *EnemyOnRadar {
eor := new(EnemyOnRadar)
eor.Moving = entities.NewMoving(50, y, 50, 50, render.NewColorBox(25, 25, color.RGBA{0, 200, 0, 0}), nil, eor.Init(), 0)
eor.Speed = physics.NewVector(-1*(rand.Float64()*2+1), rand.Float64()*2-1)
eor.Delta = eor.Speed
return eor
}

func standardEnemyMove(id int, nothing interface{}) int {
eor := event.GetEntity(id).(*EnemyOnRadar)
if eor.X() < 0 {
eor.Delta.SetPos(math.Abs(eor.Speed.X()), (eor.Speed.Y()))
}
if eor.X() > xLimit-eor.W {
eor.Delta.SetPos(-1*math.Abs(eor.Speed.X()), (eor.Speed.Y()))
}
if eor.Y() < 0 {
eor.Delta.SetPos(eor.Speed.X(), math.Abs(eor.Speed.Y()))
}
if eor.Y() > yLimit-eor.H {
eor.Delta.SetPos(eor.Speed.X(), -1*math.Abs(eor.Speed.Y()))
}
eor.ShiftX(eor.Delta.X())
eor.ShiftY(eor.Delta.Y())
return 0
}
84 changes: 84 additions & 0 deletions examples/radar-demo/radar/radar.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package radar

import (
"image"
"image/color"
"image/draw"

"github.com/oakmound/oak/render"
)

type Point struct {
X, Y *float64
}

type Radar struct {
render.LayeredPoint
points map[Point]color.Color
center Point
width, height int
r *image.RGBA
outline *render.Sprite
ratio float64
}

var (
centerColor = color.RGBA{255, 255, 0, 255}
)

// NewRadar creates a radar that will display at 0,0 with the given dimensions.
// The points given will be displayed on the radar relative to the center point,
// With the absolute distance reduced by the given ratio
func NewRadar(w, h int, points map[Point]color.Color, center Point, ratio float64) *Radar {
r := new(Radar)
r.LayeredPoint = render.NewLayeredPoint(0, 0, 0)
r.points = points
r.width = w
r.height = h
r.center = center
r.r = image.NewRGBA(image.Rect(0, 0, w, h))
r.outline = render.NewColorBox(w, h, color.RGBA{0, 0, 125, 125})
r.ratio = ratio
return r
}

// SetPos sets the position of the radar on the screen
func (r *Radar) SetPos(x, y float64) {
r.LayeredPoint.SetPos(x, y)
r.outline.SetPos(x, y)
}

// GetRGBA returns this radar's image
func (r *Radar) GetRGBA() *image.RGBA {
return r.r
}

// Draw draws the radar, satisfying render.Renderable
func (r *Radar) Draw(buff draw.Image) {
r.DrawOffset(buff, 0, 0)
}

// DrawOffset draws the radar at a given offset
func (r *Radar) DrawOffset(buff draw.Image, xOff, yOff float64) {
// Draw each point p in r.points
// at r.X() + center.X() - p.X(), r.Y() + center.Y() - p.Y()
// IF that value is < r.width/2, > -r.width/2, < r.height/2, > -r.height/2
for p, c := range r.points {
x := int((*p.X-*r.center.X)/r.ratio) + r.width/2
y := int((*p.Y-*r.center.Y)/r.ratio) + r.height/2
for x2 := x - 1; x2 < x+1; x2++ {
for y2 := y - 1; y2 < y+1; y2++ {
r.r.Set(x2, y2, c)
}
}
}
r.r.Set(r.width/2, r.height/2, centerColor)
render.ShinyDraw(buff, r.r, int(xOff+r.X()), int(yOff+r.Y()))
r.outline.DrawOffset(buff, xOff, yOff)
r.r = image.NewRGBA(image.Rect(0, 0, r.width, r.height))
}

// AddPoint adds an additional point to the radar to be tracked
func (r *Radar) AddPoint(loc Point, c color.Color) {
r.points[loc] = c
}

0 comments on commit 82938d2

Please sign in to comment.