Commit b0dc29b9 authored by Arnaud HERVOUET's avatar Arnaud HERVOUET
Browse files

Merge branch 'master' into 'main'

test

See merge request !1
parents 60dff02e 16dfff16
This diff is collapsed.
File added
/*
// Data structure for representing the running field
// used in the game. Provided with a few utilitary
// methods:
// - Draw
// - Reset
*/
package main
import (
"fmt"
"image/color"
"time"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)
type Field struct {
xstart float64 // Position of the start line for the run
xarrival float64 // Position of the arrival line for the run
chrono time.Time // Time recording of the run duration
}
// Reset allows to reset the field state in order to be able to start a new run
func (f *Field) Reset() {
f.chrono = time.Now()
}
// Draw displays the field on the screen
func (f *Field) Draw(screen *ebiten.Image, drawChrono bool) {
ebitenutil.DrawLine(screen, f.xstart, 55, f.xstart, 135, color.White)
ebitenutil.DrawLine(screen, f.xarrival, 55, f.xarrival, 135, color.White)
for i := 0; i < 5; i++ {
ebitenutil.DrawLine(screen, f.xstart, float64(55+i*20), f.xarrival, float64(55+i*20), color.White)
}
if drawChrono {
s, ms := GetSeconds(time.Since(f.chrono).Milliseconds())
ebitenutil.DebugPrintAt(screen, fmt.Sprint(s, ":", ms), screenWidth/2-25, 10)
}
}
/*
// Implementation of the Draw method for the Game structure
// This method is called once at every frame (60 frames per second)
// by ebiten, juste after calling the Update method (game-update.go)
// Provided with a few utilitary methods:
// - DrawLaunch
// - DrawResult
// - DrawRun
// - DrawSelectScreen
// - DrawWelcomeScreen
*/
package main
import (
"fmt"
"image"
"image/color"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)
// DrawWelcomeScreen displays the title screen in the game window
func (g *Game) DrawWelcomeScreen(screen *ebiten.Image) {
ebitenutil.DebugPrintAt(
screen,
fmt.Sprint("Track & Field: LP MiAR 2020-2021 Edition"),
screenWidth/2-120,
screenHeight/2-20,
)
ebitenutil.DebugPrintAt(
screen,
fmt.Sprint("Press SPACE to play"),
screenWidth/2-60,
screenHeight/2+10,
)
}
// DrawSelectScreen displays the runner selection screen in the game window
func (g *Game) DrawSelectScreen(screen *ebiten.Image) {
ebitenutil.DebugPrintAt(
screen,
fmt.Sprint("Select your player"),
screenWidth/2-60,
20,
)
xStep := (screenWidth - 100) / 8
xPadding := (xStep - 32) / 2
yPos := (screenHeight - 32) / 2
for i := 0; i < 8; i++ {
options := &ebiten.DrawImageOptions{}
xPos := 50 + i*xStep + xPadding
options.GeoM.Translate(float64(xPos), float64(yPos))
screen.DrawImage(g.runnerImage.SubImage(image.Rect(0, i*32, 32, i*32+32)).(*ebiten.Image), options)
}
for i := range g.runners {
g.runners[i].DrawSelection(screen, xStep, i)
}
}
// DrawLaunch displays the countdown before a run in the game window
func (g *Game) DrawLaunch(screen *ebiten.Image) {
if g.launchStep > 1 {
ebitenutil.DebugPrintAt(screen, fmt.Sprint(5-g.launchStep), screenWidth/2-10, 10)
}
}
// DrawRun displays the current state of the run in the game window
func (g *Game) DrawRun(screen *ebiten.Image, drawChrono bool) {
g.f.Draw(screen, drawChrono)
for i := range g.runners {
g.runners[i].Draw(screen)
}
}
// DrawResult displays the results of the run in the game window
func (g *Game) DrawResult(screen *ebiten.Image) {
ranking := [4]int{-1, -1, -1, -1}
for i := range g.runners {
rank := 0
for j := range g.runners {
if g.runners[i].runTime > g.runners[j].runTime {
rank++
}
}
for ranking[rank] != -1 {
rank++
}
ranking[rank] = i
}
for i := 1; i < g.resultStep && i <= 4; i++ {
s, ms := GetSeconds(g.runners[ranking[i-1]].runTime.Milliseconds())
ebitenutil.DebugPrintAt(screen, fmt.Sprint(i, ". P", ranking[i-1], " ", s, ":", ms), screenWidth/2-40, 55+ranking[i-1]*20)
}
if g.resultStep > 4 {
ebitenutil.DebugPrintAt(screen, "Press SPACE to restart", screenWidth/2-60, 10)
}
}
// Draw is the main drawing function of the game. It is called by ebiten at
// each frame (60 times per second) just after calling Update (game-update.go)
// Depending of the current state of the game it calls the above utilitary
// function to draw what is needed in the game window
func (g *Game) Draw(screen *ebiten.Image) {
screen.Fill(color.RGBA{141, 200, 235, 255})
switch g.state {
case StateWelcomeScreen:
g.DrawWelcomeScreen(screen)
case StateChooseRunner:
g.DrawSelectScreen(screen)
case StateLaunchRun:
g.DrawLaunch(screen)
g.DrawRun(screen, false)
case StateRun:
g.DrawRun(screen, true)
case StateResult:
g.DrawResult(screen)
g.DrawRun(screen, false)
}
}
/*
// Implementation of the Layout method for the Game structure
*/
package main
func (g *Game) Layout(width, height int) (int, int) {
return screenWidth, screenHeight
}
/*
// Implementation of the Update method for the Game structure
// This method is called once at every frame (60 frames per second)
// by ebiten, juste before calling the Draw method (game-draw.go).
// Provided with a few utilitary methods:
// - CheckArrival
// - ChooseRunners
// - HandleLaunchRun
// - HandleResults
// - HandleWelcomeScreen
// - Reset
// - UpdateAnimation
// - UpdateRunners
*/
package main
import (
"time"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
)
// HandleWelcomeScreen waits for the player to push SPACE in order to
// start the game
func (g *Game) HandleWelcomeScreen() bool {
return inpututil.IsKeyJustPressed(ebiten.KeySpace)
}
// ChooseRunners loops over all the runners to check which sprite each
// of them selected
func (g *Game) ChooseRunners() (done bool) {
done = true
for i := range g.runners {
if i == 0 {
done = g.runners[i].ManualChoose() && done
} else {
done = g.runners[i].RandomChoose() && done
}
}
return done
}
// HandleLaunchRun countdowns to the start of a run
func (g *Game) HandleLaunchRun() bool {
if time.Since(g.f.chrono).Milliseconds() > 1000 {
g.launchStep++
g.f.chrono = time.Now()
}
if g.launchStep >= 5 {
g.launchStep = 0
return true
}
return false
}
// UpdateRunners loops over all the runners to update each of them
func (g *Game) UpdateRunners() {
for i := range g.runners {
if i == 0 {
g.runners[i].ManualUpdate()
} else {
g.runners[i].RandomUpdate()
}
}
}
// CheckArrival loops over all the runners to check which ones are arrived
func (g *Game) CheckArrival() (finished bool) {
finished = true
for i := range g.runners {
g.runners[i].CheckArrival(&g.f)
finished = finished && g.runners[i].arrived
}
return finished
}
// Reset resets all the runners and the field in order to start a new run
func (g *Game) Reset() {
for i := range g.runners {
g.runners[i].Reset(&g.f)
}
g.f.Reset()
}
// UpdateAnimation loops over all the runners to update their sprite
func (g *Game) UpdateAnimation() {
for i := range g.runners {
g.runners[i].UpdateAnimation(g.runnerImage)
}
}
// HandleResults computes the resuls of a run and prepare them for
// being displayed
func (g *Game) HandleResults() bool {
if time.Since(g.f.chrono).Milliseconds() > 1000 || inpututil.IsKeyJustPressed(ebiten.KeySpace) {
g.resultStep++
g.f.chrono = time.Now()
}
if g.resultStep >= 4 && inpututil.IsKeyJustPressed(ebiten.KeySpace) {
g.resultStep = 0
return true
}
return false
}
// Update is the main update function of the game. It is called by ebiten
// at each frame (60 times per second) just before calling Draw (game-draw.go)
// Depending of the current state of the game it calls the above utilitary
// function and then it may update the state of the game
func (g *Game) Update() error {
switch g.state {
case StateWelcomeScreen:
done := g.HandleWelcomeScreen()
if done {
g.state++
}
case StateChooseRunner:
done := g.ChooseRunners()
if done {
g.UpdateAnimation()
g.state++
}
case StateLaunchRun:
done := g.HandleLaunchRun()
if done {
g.state++
}
case StateRun:
g.UpdateRunners()
finished := g.CheckArrival()
g.UpdateAnimation()
if finished {
g.state++
}
case StateResult:
done := g.HandleResults()
if done {
g.Reset()
g.state = StateLaunchRun
}
}
return nil
}
/*
// Data structure for representing a game. Implements the ebiten.Game
// interface (Update in game-update.go, Draw in game-draw.go, Layout
// in game-layout.go). Provided with a few utilitary functions:
// - initGame
*/
package main
import (
"bytes"
"course/assets"
"image"
"log"
"time"
"github.com/hajimehoshi/ebiten/v2"
)
type Game struct {
state int // Current state of the game
runnerImage *ebiten.Image // Image with all the sprites of the runners
runners [4]Runner // The four runners used in the game
f Field // The running field
launchStep int // Current step in StateLaunchRun state
resultStep int // Current step in StateResult state
}
// These constants define the five possible states of the game
const (
StateWelcomeScreen int = iota // Title screen
StateChooseRunner // Player selection screen
StateLaunchRun // Countdown before a run
StateRun // Run
StateResult // Results announcement
)
// InitGame builds a new game ready for being run by ebiten
func InitGame() (g Game) {
// Open the png image for the runners sprites
img, _, err := image.Decode(bytes.NewReader(assets.RunnerImage))
if err != nil {
log.Fatal(err)
}
g.runnerImage = ebiten.NewImageFromImage(img)
// Define game parameters
start := 50.0
finish := float64(screenWidth - 50)
frameInterval := 20
// Create the runners
for i := range g.runners {
interval := 0
if i == 0 {
interval = frameInterval
}
g.runners[i] = Runner{
xpos: start, ypos: 50 + float64(i*20),
maxFrameInterval: interval,
colorScheme: 0,
}
}
// Create the field
g.f = Field{
xstart: start,
xarrival: finish,
chrono: time.Now(),
}
return g
}
module course
go 1.15
require github.com/hajimehoshi/ebiten/v2 v2.0.6
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2 h1:Ac1OEHHkbAZ6EUnJahF0GKcU0FjPc/V8F1DvjhKngFE=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/hajimehoshi/bitmapfont/v2 v2.1.0/go.mod h1:2BnYrkTQGThpr/CY6LorYtt/zEPNzvE/ND69CRTaHMs=
github.com/hajimehoshi/ebiten/v2 v2.0.6 h1:sHNymgI+q80xasP69oFyrpup6r2qCNsKxqwsGEh6PWE=
github.com/hajimehoshi/ebiten/v2 v2.0.6/go.mod h1:uS3OjMW3f2DRDMtWoIF7yMMmrMkv+fZ6pXcwR1pfA0Y=
github.com/hajimehoshi/file2byteslice v0.0.0-20200812174855-0e5e8a80490e/go.mod h1:CqqAHp7Dk/AqQiwuhV1yT2334qbA/tFWQW0MD2dGqUE=
github.com/hajimehoshi/go-mp3 v0.3.1/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
github.com/hajimehoshi/oto v0.6.8/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
github.com/jakecoffman/cp v1.0.0/go.mod h1:JjY/Fp6d8E1CHnu74gWNnU0+b9VzEdUVPoJxg2PsTQg=
github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk=
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mobile v0.0.0-20210208171126-f462b3930c8f h1:aEcjdTsycgPqO/caTgnxfR9xwWOltP/21vtJyFztEy0=
golang.org/x/mobile v0.0.0-20210208171126-f462b3930c8f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20201009162240-fcf82128ed91/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
/*
// Implementation of a main function setting a few characteristics of
// the game window, creating a game, and launching it
*/
package main
import (
_ "image/png"
"log"
"github.com/hajimehoshi/ebiten/v2"
)
const (
screenWidth = 800 // Width of the game window (in pixels)
screenHeight = 160 // Height of the game window (in pixels)
)
func main() {
ebiten.SetWindowSize(screenWidth, screenHeight)
ebiten.SetWindowTitle("LP MiAR 2020-2021, programmation répartie")
g := InitGame()
err := ebiten.RunGame(&g)
log.Print(err)
}
/*
// Data structure for representing the four runners
// used in the game. Provided with a few utilitary
// methods:
// - CheckArrival
// - Draw
// - DrawSelection
// - ManualChoose
// - ManualUpdate
// - RandomChoose
// - RandomUpdate
// - Reset
// - UpdateAnimation
// - UpdatePos
// - UpdateSpeed
*/
package main
import (
"fmt"
"image"
"math/rand"
"time"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
"github.com/hajimehoshi/ebiten/v2/inpututil"
)
type Runner struct {
xpos, ypos float64 // Position of the runner on the screen
speed float64 // Current speed of the runner
framesSinceUpdate int // Number of frames since last speed update
maxFrameInterval int // Maximum number of frames between two speed updates
arrived bool // Tells if the runner has finished running or not
runTime time.Duration // Records the duration of the run for ranking
image *ebiten.Image // Current image used to display the runner
colorScheme int // Number of the color scheme of the runner
colorSelected bool // Tells if the color scheme is fixed or not
animationStep int // Current step of the runner animation
animationFrame int // Number of frames since the last animation step
}
// ManualUpdate allows to use the keyboard in order to control a runner
// when the game is in the StateRun state (i.e. during a run)
func (r *Runner) ManualUpdate() {
r.UpdateSpeed(inpututil.IsKeyJustPressed(ebiten.KeySpace))
r.UpdatePos()
}
// RandomUpdate allows to randomly control a runner when the game is in
// the StateRun state (i.e. during a run)
func (r *Runner) RandomUpdate() {
r.UpdateSpeed(rand.Intn(3) == 0)
r.UpdatePos()
}
// UpdateSpeed sets the speed of a runner. It is used when the game is in
// StateRun state (i.e. during a run)
func (r *Runner) UpdateSpeed(keyPressed bool) {
if !r.arrived {
r.framesSinceUpdate++
if keyPressed {
r.speed = 1500 / float64(r.framesSinceUpdate*r.framesSinceUpdate*r.framesSinceUpdate)
if r.speed > 10 {
r.speed = 10
}
r.framesSinceUpdate = 0
} else if r.framesSinceUpdate > r.maxFrameInterval {
r.speed = 0
}
}
}
// UpdatePos sets the current (x) position of a runner according to the current
// speed and the previous (x) position. It is used when the game is in StateRun
// state (i.e. during a run)
func (r *Runner) UpdatePos() {
if !r.arrived {
r.xpos += r.speed
}
}
// UpdateAnimation determines the next image that should be displayed for a
// runner, depending of whether or not the runner is running, the current
// animationStep and the current animationFrame
func (r *Runner) UpdateAnimation(runnerImage *ebiten.Image) {
r.animationFrame++
if r.speed == 0 || r.arrived {
r.image = runnerImage.SubImage(image.Rect(0, r.colorScheme*32, 32, r.colorScheme*32+32)).(*ebiten.Image)
r.animationFrame = 0
} else {
if r.animationFrame > 1 {
r.animationStep = r.animationStep%6 + 1
r.image = runnerImage.SubImage(image.Rect(32*r.animationStep, r.colorScheme*32, 32*r.animationStep+32, r.colorScheme*32+32)).(*ebiten.Image)
r.animationFrame = 0
}
}
}
// ManualChoose allows to use the keyboard for selecting the appearance of a
// runner when the game is in StateChooseRunner state (i.e. at player selection
// screen)
func (r *Runner) ManualChoose() (done bool) {
r.colorSelected =
(!r.colorSelected && inpututil.IsKeyJustPressed(ebiten.KeySpace)) ||
(r.colorSelected && !inpututil.IsKeyJustPressed(ebiten.KeySpace))
if !r.colorSelected {
if inpututil.IsKeyJustPressed(ebiten.KeyRight) {
r.colorScheme = (r.colorScheme + 1) % 8
} else if inpututil.IsKeyJustPressed(ebiten.KeyLeft) {
r.colorScheme = (r.colorScheme + 7) % 8
}