mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
parent
cea0aa72cb
commit
873bb35587
@ -163,6 +163,30 @@ func drawEbitenLogo(screen *ebiten.Image, x, y int) {
|
||||
screen.DrawTriangles(vs, is, emptySubImage, op)
|
||||
}
|
||||
|
||||
func drawArc(screen *ebiten.Image, count int) {
|
||||
var path vector.Path
|
||||
|
||||
path.MoveTo(350, 100)
|
||||
const cx, cy, r = 450, 100, 70
|
||||
theta := math.Pi * float64(count) / 180
|
||||
x := cx + r*math.Cos(theta)
|
||||
y := cy + r*math.Sin(theta)
|
||||
path.ArcTo(450, 100, float32(x), float32(y), 30)
|
||||
|
||||
op := &ebiten.DrawTrianglesOptions{
|
||||
EvenOdd: true,
|
||||
}
|
||||
vs, is := path.AppendVerticesAndIndicesForFilling(nil, nil)
|
||||
for i := range vs {
|
||||
vs[i].SrcX = 1
|
||||
vs[i].SrcY = 1
|
||||
vs[i].ColorR = 0x33 / float32(0xff)
|
||||
vs[i].ColorG = 0xcc / float32(0xff)
|
||||
vs[i].ColorB = 0x66 / float32(0xff)
|
||||
}
|
||||
screen.DrawTriangles(vs, is, emptySubImage, op)
|
||||
}
|
||||
|
||||
func maxCounter(index int) int {
|
||||
return 128 + (17*index+32)%64
|
||||
}
|
||||
@ -219,6 +243,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
||||
screen.Fill(color.White)
|
||||
drawEbitenText(screen)
|
||||
drawEbitenLogo(screen, 20, 90)
|
||||
drawArc(screen, g.counter)
|
||||
drawWave(screen, g.counter)
|
||||
|
||||
ebitenutil.DebugPrint(screen, fmt.Sprintf("TPS: %0.2f\nFPS: %0.2f", ebiten.CurrentTPS(), ebiten.CurrentFPS()))
|
||||
|
@ -18,6 +18,8 @@
|
||||
package vector
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
)
|
||||
|
||||
@ -45,7 +47,10 @@ func (p *Path) LineTo(x, y float32) {
|
||||
if len(p.segs) == 0 {
|
||||
p.segs = append(p.segs, []point{p.cur})
|
||||
}
|
||||
p.segs[len(p.segs)-1] = append(p.segs[len(p.segs)-1], point{x: x, y: y})
|
||||
seg := p.segs[len(p.segs)-1]
|
||||
if seg[len(seg)-1].x != x || seg[len(seg)-1].y != y {
|
||||
p.segs[len(p.segs)-1] = append(seg, point{x: x, y: y})
|
||||
}
|
||||
p.cur = point{x: x, y: y}
|
||||
}
|
||||
|
||||
@ -127,6 +132,56 @@ func (p *Path) cubicTo(x1, y1, x2, y2, x3, y3 float32, level int) {
|
||||
p.cubicTo(x123, y123, x23, y23, x3, y3, level+1)
|
||||
}
|
||||
|
||||
func normalize(x, y float32) (float32, float32) {
|
||||
len := float32(math.Hypot(float64(x), float64(y)))
|
||||
return x / len, y / len
|
||||
}
|
||||
|
||||
// ArcTo adds an arc curve to the path. (x1, y1) is the control point, and (x2, y2) is the destination.
|
||||
//
|
||||
// ArcTo updates the current position to (x2, y2).
|
||||
func (p *Path) ArcTo(x1, y1, x2, y2, radius float32) {
|
||||
x0 := p.cur.x
|
||||
y0 := p.cur.y
|
||||
dx0 := x0 - x1
|
||||
dy0 := y0 - y1
|
||||
dx1 := x2 - x1
|
||||
dy1 := y2 - y1
|
||||
dx0, dy0 = normalize(dx0, dy0)
|
||||
dx1, dy1 = normalize(dx1, dy1)
|
||||
|
||||
// theta is the angle between two vectors (dx0, dy0) and (dx1, dy1).
|
||||
theta := math.Acos(float64(dx0*dx1 + dy0*dy1))
|
||||
// TODO: When theta is bigger than π/2, the arc should be split into two.
|
||||
|
||||
// dist is the distance between the control point and the arc's begenning and ending points.
|
||||
dist := radius / float32(math.Tan(theta/2))
|
||||
|
||||
// TODO: What if dist is too big?
|
||||
|
||||
// (ax0, ay0) is the start of the arc.
|
||||
ax0 := x1 + dx0*dist
|
||||
ay0 := y1 + dy0*dist
|
||||
|
||||
// (ax1, ay1) is the end of the arc.
|
||||
ax1 := x1 + dx1*dist
|
||||
ay1 := y1 + dy1*dist
|
||||
|
||||
p.LineTo(ax0, ay0)
|
||||
|
||||
// Calculate the control points for an approximated Bézier curve.
|
||||
// See https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/curves/beziers.
|
||||
alpha := math.Pi - theta
|
||||
l := radius * float32(math.Tan(alpha/4)*4/3)
|
||||
cx0 := ax0 + l*(-dx0)
|
||||
cy0 := ay0 + l*(-dy0)
|
||||
cx1 := ax1 + l*(-dx1)
|
||||
cy1 := ay1 + l*(-dy1)
|
||||
p.CubicTo(cx0, cy0, cx1, cy1, ax1, ay1)
|
||||
|
||||
p.LineTo(x2, y2)
|
||||
}
|
||||
|
||||
// AppendVerticesAndIndicesForFilling appends vertices and indices to fill this path and returns them.
|
||||
// AppendVerticesAndIndicesForFilling works in a similar way to the built-in append function.
|
||||
// If the arguments are nils, AppendVerticesAndIndices returns new slices.
|
||||
|
Loading…
Reference in New Issue
Block a user