summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordavidovski <david@davidovski.xyz>2024-04-21 19:34:12 +0100
committerdavidovski <david@davidovski.xyz>2024-04-21 19:34:12 +0100
commit64757d18c4b2669c46f2dc88293cf2f0ea1887db (patch)
tree865a8fe4fb25180583ebf93fca40073c3d48822e
parent1f1c464f84a169ea5146d360ae6b1211d8a7074f (diff)
Add reversing
-rw-r--r--main.go243
-rw-r--r--player.go1
-rw-r--r--tilemap.go6
3 files changed, 201 insertions, 49 deletions
diff --git a/main.go b/main.go
index f0448b3..d518abc 100644
--- a/main.go
+++ b/main.go
@@ -3,88 +3,172 @@ package main
import (
"log"
"image"
+ "image/color"
+ _ "embed"
_ "image/png"
+ "github.com/hajimehoshi/ebiten/v2/inpututil"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)
const (
- screenWidth = 240
+ screenWidth = 400
screenHeight = 240
tileSize = 16
playerSpeed = 0.2
jumpHeight = 0.2
+ rewindSpeed = 2
)
+var (
+ //go:embed shaders/none.kage
+ noneShader_src []byte
+ //go:embed shaders/vcr.kage
+ vcrShader_src []byte
+
+ //go:embed shaders/reverse.kage
+ rewindShader_src []byte
+)
+
+var (
+ shaders map[string]*ebiten.Shader
+)
+
+type State int
+
+const (
+ IN_GAME State = iota
+ END
+ REVERSING
+)
+
+type RecPoint struct {
+ x float32
+ y float32
+ vx float32
+ vy float32
+}
+
+
type Game struct {
+ surface *ebiten.Image
tilemap *Tilemap
offsetX int
offsetY int
player *GameObject
+ startPosition *GameObject
+ exit *GameObject
+ objects []*GameObject
+ time int
+ shaderName string
+ recording [][]RecPoint
+ state State
}
-func (g * Game)InitPlayer() {
- g.player = &GameObject{
- x: 5,
- y: 5,
+func (g * Game)RecordPoint() {
+ points := []RecPoint{}
+ for _, object := range g.objects {
+ points = append(points, RecPoint{
+ x: object.x,
+ y: object.y,
+ vx: object.vx,
+ vy: object.vy,
+ })
+ }
+ g.recording = append(g.recording, points)
+}
+
+func (g * Game)ReplayPoint() {
+ if len(g.recording) == 0 {
+ return
}
+ var points []RecPoint
+ points, g.recording = g.recording[len(g.recording)-1], g.recording[:len(g.recording)-1]
+ for i, point := range points {
+ g.objects[i].x = point.x
+ g.objects[i].y = point.y
+ g.objects[i].vx = point.vx
+ g.objects[i].vy = point.vy
+ }
+}
+
+func (g * Game)InitPlayer() {
+ g.player = &GameObject{}
+
playerImage, _, err := ebitenutil.NewImageFromFile("Assets/Main Characters/Ninja Frog/Idle (32x32).png")
if err != nil {
log.Fatal(err)
}
g.player.image = playerImage.SubImage(image.Rect(0, 0, 32, 32)).(*ebiten.Image)
+ g.objects = append(g.objects, g.player)
+
+ g.ResetPlayer()
+}
+
+func (g * Game)ResetPlayer() {
+ g.player.x = g.startPosition.x
+ g.player.y = g.startPosition.y - 0.1
+}
+
+func (g * Game)InitExit() {
+ g.exit = &GameObject{
+ x: 21,
+ y: 8,
+ }
+
+ exitImage, _, err := ebitenutil.NewImageFromFile("tiles.png")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ g.exit.image = exitImage.SubImage(image.Rect(0, 16, 32, 48)).(*ebiten.Image)
+ g.objects = append(g.objects, g.exit)
}
func (g *Game) Init() {
+ g.state = IN_GAME
+
+ g.surface = ebiten.NewImage(screenWidth, screenHeight)
+ g.shaderName = "none"
tilemap := NewTilemap([][]int{
{
- 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243,
- 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243,
- 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243,
- 243, 218, 243, 243, 243, 243, 243, 243, 243, 243, 243, 218, 243, 244, 243,
- 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243,
- 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243,
- 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243,
- 243, 243, 244, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243,
- 243, 243, 243, 243, 243, 243, 243, 243, 243, 219, 243, 243, 243, 219, 243,
- 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243,
- 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243,
- 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243,
- 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243,
- 243, 218, 243, 243, 243, 243, 243, 243, 243, 243, 243, 244, 243, 243, 243,
- 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243,
- },
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
- 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29,
- 29, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 51,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0,
+ 0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0,
+ 0, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
},
- }, 15)
+ }, 25)
+
+ g.startPosition = &GameObject{
+ x: 4,
+ y: 8,
+ }
+
g.tilemap = &tilemap
g.tilemap.UpdateSurface()
g.InitPlayer()
+ g.InitExit()
ebiten.SetWindowSize(screenWidth*2, screenHeight*2)
- ebiten.SetWindowTitle("Tiles (Ebitengine Demo)")
+ ebiten.SetWindowTitle("Reverse")
if err := ebiten.RunGame(g); err != nil {
log.Fatal(err)
}
@@ -92,6 +176,19 @@ func (g *Game) Init() {
}
func (g *Game) Update() error {
+ g.time += 1
+
+ if inpututil.IsKeyJustPressed(ebiten.KeyR) {
+ if g.state == REVERSING {
+ g.state = IN_GAME
+ g.shaderName = "none"
+ } else {
+ g.state = REVERSING
+ g.shaderName = "vcr"
+ }
+
+ }
+
if ebiten.IsKeyPressed(ebiten.KeyLeft) || ebiten.IsKeyPressed(ebiten.KeyA) {
g.player.vx = -playerSpeed
}
@@ -104,24 +201,80 @@ func (g *Game) Update() error {
g.player.vy = -jumpHeight
}
- g.player.Update(*g.tilemap)
- return g.tilemap.Update()
+ if g.state == IN_GAME {
+ for _, obj := range g.objects {
+ obj.Update(*g.tilemap)
+ }
+
+ g.tilemap.Update()
+ g.RecordPoint()
+ }
+
+ if g.state == REVERSING {
+ for x := 0; x < rewindSpeed; x++ {
+ g.ReplayPoint()
+ }
+ }
+
+ return nil
}
func (g *Game) Draw(screen *ebiten.Image) {
+
+ g.surface.Fill(color.Alpha16{0x9ccf})
+
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(g.offsetX), float64(g.offsetY))
- screen.DrawImage(g.tilemap.surface, op)
- g.player.Draw(screen, *g.tilemap)
- ebitenutil.DebugPrint(screen, "Hello, World!")
+ g.surface.DrawImage(g.tilemap.surface, op)
+
+ for i := len(g.objects)-1; i >= 0; i-- {
+ obj := g.objects[i]
+ obj.Draw(g.surface, *g.tilemap)
+ }
+
+ cx, cy := ebiten.CursorPosition()
+
+ shop := &ebiten.DrawRectShaderOptions{}
+ shop.Uniforms = map[string]any{
+ "Time": float32(g.time) / 60,
+ "Cursor": []float32{float32(cx), float32(cy)},
+ }
+ shop.Images[0] = g.surface
+ shop.Images[1] = g.surface
+ shop.Images[2] = g.surface
+ shop.Images[3] = g.surface
+ screen.DrawRectShader(screenWidth, screenHeight, shaders[g.shaderName], shop)
+
+ //screen.DrawImage(surface, &ebiten.DrawImageOptions{})
}
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int){
return screenWidth, screenHeight
}
+func LoadShaders() error {
+ if shaders == nil {
+ shaders = map[string]*ebiten.Shader{}
+ }
+ var err error
+
+ shaders["none"], err = ebiten.NewShader([]byte(noneShader_src))
+ if err != nil {
+ return err
+ }
+
+ shaders["vcr"], err = ebiten.NewShader([]byte(vcrShader_src))
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
func main() {
+ LoadShaders()
+
ebiten.SetWindowTitle("Hello, World!")
game := &Game{}
game.Init()
diff --git a/player.go b/player.go
index 0b313ed..4fe7aa8 100644
--- a/player.go
+++ b/player.go
@@ -36,7 +36,6 @@ func (o * GameObject) Update(tilemap Tilemap) {
o.onGround = true;
o.vx *= friction
-
o.y -= o.vy
o.vy = 0
} else {
diff --git a/tilemap.go b/tilemap.go
index 281e76a..b24bdb6 100644
--- a/tilemap.go
+++ b/tilemap.go
@@ -56,7 +56,7 @@ func (tm *Tilemap) UpdateSurface() {
func NewTilemap(layers [][]int, mapWidth int) Tilemap {
tilemap := Tilemap{
tileSize: 16,
- mapWidth: 15,
+ mapWidth: 25,
}
tilemap.layers = layers
@@ -64,7 +64,7 @@ func NewTilemap(layers [][]int, mapWidth int) Tilemap {
tilemap.surface = ebiten.NewImage(mapWidth*tilemap.tileSize, len(layers[0])/mapWidth*tilemap.tileSize)
var err error
- tilemap.tilesImage, _, err = ebitenutil.NewImageFromFile("Assets/Terrain/Terrain (16x16).png")
+ tilemap.tilesImage, _, err = ebitenutil.NewImageFromFile("tiles.png")
if err != nil {
log.Fatal(err)
@@ -76,7 +76,7 @@ func NewTilemap(layers [][]int, mapWidth int) Tilemap {
}
func (tm * Tilemap) CalculateCollisions() {
- for i, t := range tm.layers[1] {
+ for i, t := range tm.layers[0] {
if t != 0 {
x := i%tm.mapWidth * tm.tileSize
y := i/tm.mapWidth * tm.tileSize