diff options
| -rw-r--r-- | main.go | 146 | ||||
| -rw-r--r-- | player.go | 52 | ||||
| -rw-r--r-- | shaders/none.kage | 12 | ||||
| -rw-r--r-- | shaders/vcr.kage | 44 | ||||
| -rw-r--r-- | tilemap.go | 12 | 
5 files changed, 149 insertions, 117 deletions
@@ -1,24 +1,27 @@  package main  import ( +	_ "embed" +	"fmt" +	"image/color" +	_ "image/png"  	"log" -    "image" -    "image/color" -    _ "embed" -    _ "image/png" +	"math" -	"github.com/hajimehoshi/ebiten/v2/inpututil"  	"github.com/hajimehoshi/ebiten/v2"  	"github.com/hajimehoshi/ebiten/v2/ebitenutil" +	"github.com/hajimehoshi/ebiten/v2/inpututil"  )  const (      screenWidth = 400      screenHeight = 240      tileSize = 16 -    playerSpeed = 0.2 -    jumpHeight = 0.2 +    playerSpeed = 2.1 +    jumpHeight = 3.2      rewindSpeed = 2 +    gravity = 0.16 +    friction = 0.9  )  var ( @@ -26,13 +29,11 @@ var (  	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 +    tilesImage *ebiten.Image  )  type State int @@ -40,6 +41,7 @@ type State int  const (  	IN_GAME State = iota  	END +	PLACING      REVERSING  ) @@ -64,6 +66,7 @@ type Game struct {      shaderName string      recording [][]RecPoint      state State +    toPlace []*GameObject  }  func (g * Game)RecordPoint() { @@ -94,42 +97,20 @@ func (g * Game)ReplayPoint() {      }  } -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, +func (g * Game)ResetAll() { +    for _, obj := range g.objects { +        obj.x = obj.startx +        obj.y = obj.starty      } - -    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.state = PLACING + +    g.toPlace = append(g.toPlace, NewBox(0, 0)) +    g.toPlace = append(g.toPlace, NewBox(0, 0)) +    g.toPlace = append(g.toPlace, NewBox(0, 0)) +    g.toPlace = append(g.toPlace, NewSpring(0, 0))      g.surface = ebiten.NewImage(screenWidth, screenHeight)      g.shaderName = "none" @@ -154,17 +135,16 @@ func (g *Game) Init() {  			},  		}, 25) -    g.startPosition = &GameObject{ -        x: 4, -        y: 8, -    } -      g.tilemap = &tilemap      g.tilemap.UpdateSurface() -    g.InitPlayer() -    g.InitExit() +    g.player = NewPlayer(4 * tileSize, 8 * tileSize) +    g.objects = append(g.objects, g.player) +    g.exit = NewExit(21 * tileSize, 8 * tileSize) +    g.objects = append(g.objects, g.exit) + +    g.ResetAll()  	ebiten.SetWindowSize(screenWidth*2, screenHeight*2) @@ -182,28 +162,30 @@ func (g *Game) Update() error {          if g.state == REVERSING {              g.state = IN_GAME              g.shaderName = "none" -        } else  { +        } + +        if g.state == IN_GAME {              g.state = REVERSING              g.shaderName = "vcr"          }      } -    if ebiten.IsKeyPressed(ebiten.KeyLeft) || ebiten.IsKeyPressed(ebiten.KeyA) { -        g.player.vx = -playerSpeed -    } +    if g.state == IN_GAME { +        if ebiten.IsKeyPressed(ebiten.KeyLeft) || ebiten.IsKeyPressed(ebiten.KeyA) { +            g.player.vx = -playerSpeed +        } -    if ebiten.IsKeyPressed(ebiten.KeyRight) || ebiten.IsKeyPressed(ebiten.KeyD) { -        g.player.vx = playerSpeed -    } +        if ebiten.IsKeyPressed(ebiten.KeyRight) || ebiten.IsKeyPressed(ebiten.KeyD) { +            g.player.vx = playerSpeed +        } -    if g.player.onGround && (ebiten.IsKeyPressed(ebiten.KeySpace) || ebiten.IsKeyPressed(ebiten.KeyUp)) { -        g.player.vy = -jumpHeight -    } +        if g.player.onGround && (ebiten.IsKeyPressed(ebiten.KeySpace) || ebiten.IsKeyPressed(ebiten.KeyUp)) { +            g.player.vy += -jumpHeight +        } -    if g.state == IN_GAME {          for _, obj := range g.objects { -            obj.Update(*g.tilemap) +            obj.Update(*g.tilemap, g.objects)          }          g.tilemap.Update() @@ -216,9 +198,38 @@ func (g *Game) Update() error {          }      } +    if g.state == PLACING { +        if len(g.toPlace) > 0 { +            cx, cy := ebiten.CursorPosition() +            cx = int(math.Floor(float64(cx)/float64(g.tilemap.tileSize)))*g.tilemap.tileSize +            cy = int(math.Floor(float64(cy)/float64(g.tilemap.tileSize)))*g.tilemap.tileSize + +            g.toPlace[0].x = float32(cx) +            g.toPlace[0].y = float32(cy) + +            if inpututil.IsMouseButtonJustPressed(ebiten.MouseButton0) { +                g.PlaceObject(cx, cy) +            } +        } +    } +      return nil  } +func (g *Game)PlaceObject(cx, cy int) { +        g.toPlace[0].startx = float32(cx) +        g.toPlace[0].starty = float32(cy) + +        g.objects = append(g.objects, g.toPlace[0]) + +        g.toPlace = g.toPlace[1:len(g.toPlace)] + +        if len(g.toPlace) == 0 { +            g.ResetAll() +            g.state = IN_GAME +        } +} +  func (g *Game) Draw(screen *ebiten.Image) {      g.surface.Fill(color.Alpha16{0x9ccf}) @@ -233,6 +244,12 @@ func (g *Game) Draw(screen *ebiten.Image) {          obj.Draw(g.surface, *g.tilemap)      } +    if g.state == PLACING { +        if len(g.toPlace) > 0 { +            g.toPlace[0].Draw(g.surface, *g.tilemap) +        } +    } +      cx, cy := ebiten.CursorPosition()  	shop := &ebiten.DrawRectShaderOptions{} @@ -246,6 +263,7 @@ func (g *Game) Draw(screen *ebiten.Image) {  	shop.Images[3] = g.surface  	screen.DrawRectShader(screenWidth, screenHeight, shaders[g.shaderName], shop) +    ebitenutil.DebugPrint(screen, fmt.Sprintf("TPS: %0.2f", ebiten.ActualTPS()))      //screen.DrawImage(surface, &ebiten.DrawImageOptions{})  } @@ -275,6 +293,12 @@ func LoadShaders() error {  func main() {      LoadShaders() +    var err error +    tilesImage, _, err = ebitenutil.NewImageFromFile("tiles.png") +	if err != nil { +		log.Fatal(err) +	} +  	ebiten.SetWindowTitle("Hello, World!")      game := &Game{}      game.Init() diff --git a/player.go b/player.go deleted file mode 100644 index 4fe7aa8..0000000 --- a/player.go +++ /dev/null @@ -1,52 +0,0 @@ -package main - -import ( -    "github.com/hajimehoshi/ebiten/v2" -) - -const ( -    gravity = 0.01 -    friction = 0.6 -) - -type GameObject struct { -    x, y float32 -    vx, vy float32 -    image *ebiten.Image -    onGround bool -} - - -type Player struct { -    GameObject -} - -func (o * GameObject) Update(tilemap Tilemap) { -    o.vy += gravity - -    o.x += o.vx -    if tilemap.CollideObject(o) { -        o.x -= o.vx -        o.vx = 0 -    } - -    o.y += o.vy -    if (tilemap.CollideObject(o)) { - -        o.onGround = true; -        o.vx *= friction - -        o.y -= o.vy -        o.vy = 0 -    } else { -        o.onGround = false; -    } -} - -func (o * GameObject) Draw(screen *ebiten.Image, tilemap Tilemap) { -    op := &ebiten.DrawImageOptions{} -    op.GeoM.Translate(float64(o.x * float32(tilemap.tileSize)), float64(o.y * float32(tilemap.tileSize))) -    screen.DrawImage(o.image, op) -} - - diff --git a/shaders/none.kage b/shaders/none.kage new file mode 100644 index 0000000..3eccc50 --- /dev/null +++ b/shaders/none.kage @@ -0,0 +1,12 @@ +//go:build ignore + +//kage:unit pixels + +package main + +var Time float +var Cursor vec2 + +func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 { +    return imageSrc2UnsafeAt(srcPos); +} diff --git a/shaders/vcr.kage b/shaders/vcr.kage new file mode 100644 index 0000000..3bee5cd --- /dev/null +++ b/shaders/vcr.kage @@ -0,0 +1,44 @@ +//go:build ignore + +//kage:unit pixels + +package main + +var Time float +var Cursor vec2 + +const noiseX = 80.0 +const noiseY = 100.0 + +const colorOffsetIntensity = 1.2 + +func rand(co vec2) float { +    return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453); +} + +func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 { +    noiseOffset := Time / 7 +    col := vec4(0) +    uv := srcPos / imageSrc0Size() + +    uv.x = uv.x + (rand(vec2(Time,srcPos.y)) - 0.5) / (noiseX);  +    uv.y = uv.y + (rand(vec2(Time))-0.5) / (noiseY); + +    whiteNoise := rand(vec2(floor(uv.y*80.0),floor(uv.x*50.0))+vec2(Time,0)) +    off := 1.0 - mod(uv.y - noiseOffset, 1) + +    if (whiteNoise > 11.5-30.0*(off)) || whiteNoise < 1.5-2.0*(off) { +        // Sample the texture. + +        offsetR := vec2(0.006 * sin(Time), 0.0) * colorOffsetIntensity; +        offsetG := vec2(0.0073 * (cos(Time * 0.97)), 0.0) * colorOffsetIntensity; +        r := imageSrc0UnsafeAt((uv+offsetR) * imageSrc0Size()).r +        g := imageSrc0UnsafeAt((uv+offsetG) * imageSrc0Size()).g +        b := imageSrc0UnsafeAt(uv * imageSrc0Size()).b +        return vec4(r, g, b, 1.0) +    } else { +    	col = imageSrc2UnsafeAt(uv * imageSrc0Size()); +        return col + vec4(0.8); +    } + +} @@ -5,7 +5,6 @@ import (      "log"      "image"      _ "image/png" -	"github.com/hajimehoshi/ebiten/v2/ebitenutil"  ) @@ -64,7 +63,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("tiles.png") +	tilemap.tilesImage = tilesImage  	if err != nil {  		log.Fatal(err) @@ -89,6 +88,11 @@ func (tm * Tilemap) CalculateCollisions() {      }  } + +func Collide(r1 image.Rectangle, r2 image.Rectangle) bool { +    return ! ( r2.Min.X > r1.Max.X || r2.Max.X < r1.Min.X || r2.Min.Y > r1.Max.Y || r2.Max.Y < r1.Min.Y) +} +  func (t * Tilemap) Collide(x, y, width, height int) bool {      r1 :=  image.Rect(          x, @@ -111,8 +115,8 @@ func (t * Tilemap) Collide(x, y, width, height int) bool {  func (t * Tilemap) CollideObject(object *GameObject) bool {      width := object.image.Bounds().Dx()      height := object.image.Bounds().Dy() -    x := int(object.x*float32(t.tileSize)) -    y := int(object.y*float32(t.tileSize)) +    x := int(object.x) +    y := int(object.y)      return t.Collide(x, y, width, height)  }  | 
