diff options
-rw-r--r-- | pengui.go | 152 |
1 files changed, 121 insertions, 31 deletions
@@ -11,6 +11,10 @@ import ( "github.com/hajimehoshi/ebiten/v2/vector" ) +const GROUND_RESISTANCE = 0.8 +const AIR_RESISTANCE = 0.99 +var red = color.RGBA{0xcc, 0x66, 0x66, 0xff} +var green = color.RGBA{0xb5, 0xbd, 0x68, 0xff} const screen_w, screen_h = 640, 480 type Penguin struct { @@ -18,6 +22,7 @@ type Penguin struct { x, y float64 xv, yv float64 + onGround bool } func newPenguin() Penguin { @@ -37,34 +42,92 @@ func newPenguin() Penguin { return penguin; } -func (penguin *Penguin) draw(screen *ebiten.Image) { +func (p *Penguin) Width() (float64) { + return float64(p.img.Bounds().Dx()) +} + +func (p *Penguin) Height() (float64) { + return float64(p.img.Bounds().Dy()) +} + +func (p *Penguin) Cx() (float64) { + return p.x + float64(p.img.Bounds().Dx()) / 2 +} + +func (p *Penguin) Cy() (float64) { + return p.y + float64(p.img.Bounds().Dy()) / 2 +} + +func (penguin *Penguin) draw(screen *ebiten.Image, game Game) { op := &ebiten.DrawImageOptions{} - op.GeoM.Translate(penguin.x, penguin.y) + + if penguin.onGround { + angle := game.ground.angle(penguin.Cx(), 2) + tx, ty := float64(penguin.Width()) / 2, float64(penguin.Height()) + + op.GeoM.Translate(-tx, -ty) + op.GeoM.Rotate(angle) + op.GeoM.Translate(tx, ty) + } + + op.GeoM.Translate(penguin.x, penguin.y) screen.DrawImage(penguin.img, op) } -func (penguin *Penguin) drawBounds(screen *ebiten.Image) { +func (penguin *Penguin) drawBounds(screen *ebiten.Image, game Game) { + + var m float64 = 16 + + vector.StrokeLine(screen, + float32(penguin.Cx()), float32(penguin.y+penguin.Height()), + float32(penguin.Cx() + penguin.xv*m), float32(penguin.y + penguin.Height() + penguin.yv*m), + 4, red, true) + + if penguin.onGround{ + fx, fy := Normalize(game.ground.normal(game.penguin.Cx(), 2)) + vector.StrokeLine(screen, + float32(penguin.Cx()), float32(penguin.y+penguin.Height()), + float32(penguin.Cx() + fx*penguin.Height()), float32(penguin.y + penguin.Height() + fy*penguin.Height()), + 4, green, true) + return + } + vector.StrokeRect(screen, float32(penguin.x), float32(penguin.y), - float32(penguin.img.Bounds().Dx()), float32(penguin.img.Bounds().Dy()), - 4, color.RGBA{0xcc, 0x66, 0x66, 0xff}, true) + float32(penguin.Width()), float32(penguin.Height()), + 4, red, true) + + } func (penguin *Penguin) update(g *Game) { - if penguin.collideWithCurve(g.ground, penguin.xv, 0){ - penguin.xv = 0 - penguin.yv -= 4 - } else { + if penguin.onGround{ + penguin.yv = 0 + penguin.y = g.ground(penguin.Cx()) - float64(penguin.img.Bounds().Dy()) penguin.x += penguin.xv - penguin.xv *= 0.9 + penguin.y += penguin.yv + + dx, dy := Normalize(g.ground.normal(penguin.x, 1)) + penguin.xv += math.Sqrt(dx*dx + dy*dy) * math.Sin(g.ground.angle(penguin.Cx(), 2)) * 4 + //penguin.yv += math.Sqrt(dx*dx + dy*dy) * math.Cos(g.ground.angle(penguin.Cx(), 2)) * 4 + penguin.xv *= GROUND_RESISTANCE + + return } + penguin.yv += 0.9 + + penguin.x += penguin.xv + penguin.y += penguin.yv + + penguin.xv *= AIR_RESISTANCE + penguin.yv *= AIR_RESISTANCE + if penguin.collideWithCurve(g.ground, 0, penguin.yv){ penguin.yv = 0 - } else { - penguin.y += penguin.yv - penguin.yv += 0.9 - } + penguin.onGround = true + return + } } func (p *Penguin) collideWithCurve(curve Curve, xv, yv float64) bool { @@ -100,26 +163,51 @@ func (curve Curve) draw(dst *ebiten.Image, clr color.Color, width float32, resol } } +func (curve Curve) delta(x, r float64) (float64, float64){ + x1, x2 := x + r, x - r + y1, y2 := curve(x1), curve(x2) + dx, dy := x2 - x1, y2 - y1 + return dx, dy +} + +func (curve Curve) angle(x, r float64) (float64){ + dx, dy := curve.delta(x, r) + return math.Atan(dy / dx) +} + +func (curve Curve) normal(x, r float64) (float64, float64){ + dx, dy := curve.delta(x, r) + //m := -(dx / dy) + return -dy,dx +} + +func Normalize(x, y float64) (float64, float64) { + m := math.Sqrt(x*x + y*y) + return x/m, y/m +} + type Game struct{ penguin Penguin ground Curve } func (g *Game) Update() error { - if ebiten.IsKeyPressed(ebiten.KeyArrowRight) { - g.penguin.xv = 4 - } - - if ebiten.IsKeyPressed(ebiten.KeyArrowLeft) { - g.penguin.xv = -4 - } - - if ebiten.IsKeyPressed(ebiten.KeyArrowUp) { - g.penguin.yv = -4 - } - - if ebiten.IsKeyPressed(ebiten.KeyArrowDown) { - g.penguin.yv = 4 + if g.penguin.onGround{ + if ebiten.IsKeyPressed(ebiten.KeyA) { + g.penguin.xv = -4 + } + + if ebiten.IsKeyPressed(ebiten.KeyD) { + g.penguin.xv = 4 + } + + if ebiten.IsKeyPressed(ebiten.KeySpace) { + g.penguin.onGround = false + fx, fy := Normalize(g.ground.normal(g.penguin.Cx(), 2)) + const jumpHeight = 8 + g.penguin.xv += fx * jumpHeight + g.penguin.yv += fy * jumpHeight + } } g.penguin.update(g) @@ -131,8 +219,8 @@ func (g *Game) Draw(screen *ebiten.Image) { screen.Fill(color.RGBA{0xfe, 0xfe, 0xfe, 0xff}) g.ground.draw(screen, color.RGBA{0x19, 0x19, 0x19, 0xff}, 4, 16, true); - g.penguin.draw(screen) - g.penguin.drawBounds(screen) + g.penguin.draw(screen, *g) + g.penguin.drawBounds(screen, *g) } func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) { @@ -146,7 +234,9 @@ func main() { game := Game{} game.ground = func(x float64)(y float64) { - return 200-math.Pow((x - 320)/320, 3)+math.Pow((x-320), 2)/300 + //return 200-math.Pow((x - 320)/320, 3)+math.Pow((x-320), 2)/300 + //return 400 + return 400+50*math.Sin(x/50) } game.init() |