diff options
-rw-r--r-- | assets/tiles.png | bin | 1416 -> 4259 bytes | |||
-rw-r--r-- | level.go | 46 | ||||
-rw-r--r-- | main.go | 57 | ||||
-rw-r--r-- | objects.go | 5 | ||||
-rw-r--r-- | shaders/bloom.kage | 43 | ||||
-rw-r--r-- | shaders/clouds.kage | 11 | ||||
-rw-r--r-- | shaders/none.kage | 4 | ||||
-rw-r--r-- | shaders/vcr_lite.kage | 33 |
8 files changed, 153 insertions, 46 deletions
diff --git a/assets/tiles.png b/assets/tiles.png Binary files differindex 5c3ce91..4ee5ff8 100644 --- a/assets/tiles.png +++ b/assets/tiles.png @@ -30,6 +30,10 @@ func levelStart(g *Game) { } } +func StartGame(g *Game) { + StartLevel4(g) +} + func StartLevel1(g *Game ) { g.SetInGame() @@ -46,11 +50,11 @@ func StartLevel1(g *Game ) { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, + 0, 0, 51, 36, 34, 35, 36, 34, 35, 36, 34, 35, 36, 34, 35, 36, 34, 35, 36, 34, 35, 36, 34, 67, 0, + 0, 50, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 0, + 0, 53, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 0, + 0, 69, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 0, + 0, 69, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 0, }, }, 25) @@ -102,22 +106,22 @@ func StartLevel4(g *Game) { g.ClearAll() tilemap := NewTilemap([][]int{ { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 3, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 0, - 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 36, 34, 35, 36, 34, 35, 36, 34, 67, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 0, + 0, 0, 51, 36, 34, 35, 36, 34, 35, 36, 34, 35, 36, 34, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 0, + 0, 50, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 55, 53, 54, 0, + 0, 53, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 71, 69, 70, 0, + 0, 69, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, 37, 38, 39, }, }, 25) @@ -43,9 +43,10 @@ var ( noneShader_src []byte //go:embed shaders/vcr.kage vcrShader_src []byte - //go:embed shaders/clouds.kage cloudShader_src []byte + //go:embed shaders/bloom.kage + bloomShader_src []byte //go:embed assets/tiles.png tilesPng_src []byte @@ -217,7 +218,7 @@ func (g *Game) Init() { g.objects = append(g.objects, g.exit) g.ResetAll() - StartLevel1(g) + StartGame(g) g.audioPlayer.ambientAudio.SetVolume(0) @@ -377,24 +378,46 @@ func DrawBackground(screen *ebiten.Image, time int) { screen.DrawRectShader(screenWidth, screenHeight, shaders["sky"], shop) } +func PostProcess(screen *ebiten.Image, shaderName string, time int) { + w, h := screen.Bounds().Dx(), screen.Bounds().Dy() + for _, shader := range []string{shaderName} { + out := ebiten.NewImage(w, h) + shop := &ebiten.DrawRectShaderOptions{} + + shop.Uniforms = map[string]any{ + "Time": float32(time) / 60, + "NoiseOffset": float32(time) / 60, + } + shop.Images[0] = screen + shop.Images[1] = screen + shop.Images[2] = screen + shop.Images[3] = screen + out.DrawRectShader(w, h, shaders[shader], shop) + + op := &ebiten.DrawImageOptions{} + screen.DrawImage(out, op) + } + +} + func (g *Game) Draw(screen *ebiten.Image) { g.surface.Fill(color.Alpha16{0x9ccf}) DrawBackground(g.surface, g.time) op := &ebiten.DrawImageOptions{} - op.GeoM.Translate(float64(g.offsetX), float64(g.offsetY)) + op.GeoM.Translate(float64(g.offsetX), float64(g.offsetY-2)) 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) + obj.Draw(obj, g.surface, *g.tilemap) } if g.state == PLACING { if len(g.toPlace) > 0 { - g.toPlace[0].Draw(g.surface, *g.tilemap) + g.toPlace[0].Draw(g.toPlace[0], g.surface, *g.tilemap) } } @@ -409,19 +432,13 @@ func (g *Game) Draw(screen *ebiten.Image) { } } - shop := &ebiten.DrawRectShaderOptions{} - shop.Uniforms = map[string]any{ - "Time": float32(g.time) / 60, - "NoiseOffset": float32(g.time) / 60, - } - 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) - - ebitenutil.DebugPrint(screen, fmt.Sprintf("shader: %s", g.shaderName)) - //screen.DrawImage(surface, &ebiten.DrawImageOptions{}) + + op = &ebiten.DrawImageOptions{} + PostProcess(g.surface, g.shaderName, g.time) + + op = &ebiten.DrawImageOptions{} + screen.DrawImage(g.surface, &ebiten.DrawImageOptions{}) + ebitenutil.DebugPrint(screen, fmt.Sprintf("tps: %.4f", ebiten.ActualFPS())) } func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int){ @@ -443,6 +460,10 @@ func LoadShaders() error { if err != nil { return err } + shaders["bloom"], err = ebiten.NewShader([]byte(bloomShader_src)) + if err != nil { + return err + } shaders["sky"], err = ebiten.NewShader([]byte(cloudShader_src)) if err != nil { @@ -40,6 +40,7 @@ type GameObject struct { onCollideDown func(this, other *GameObject) bool onCollideLeft func(this, other *GameObject) bool onCollideRight func(this, other *GameObject) bool + Draw func (o * GameObject, screen *ebiten.Image, tilemap Tilemap) movable bool } @@ -132,7 +133,7 @@ func (o * GameObject) HasCollision(tilemap Tilemap, others []*GameObject, dir Di return false } -func (o * GameObject) Draw(screen *ebiten.Image, tilemap Tilemap) { +func DrawObject(o * GameObject, screen *ebiten.Image, tilemap Tilemap) { op := &ebiten.DrawImageOptions{} op.ColorScale.ScaleAlpha(o.alpha) op.GeoM.Translate(float64(o.x), float64(o.y)) @@ -199,6 +200,7 @@ func NewObject(game *Game, x, y float32) *GameObject{ x: x, y: y, movable: true, + Draw: DrawObject, } } @@ -208,6 +210,7 @@ func NewPlayer(game *Game, x, y float32) *GameObject{ playerImage := ebiten.NewImageFromImage(characterImage) player.image = playerImage.SubImage(image.Rect(4, 8, 27, 32)).(*ebiten.Image) + player.Draw = DrawObject player.movable = false return player diff --git a/shaders/bloom.kage b/shaders/bloom.kage new file mode 100644 index 0000000..fc987b1 --- /dev/null +++ b/shaders/bloom.kage @@ -0,0 +1,43 @@ +//go:build ignore +//kage:unit pixels + +package main + +const THRESHOLD = .9 +const DIRECTIONS = 30.0 // BLUR DIRECTIONS (Default 16.0 - More is better but slower) +const QUALITY = 12.0 // BLUR QUALITY (Default 4.0 - More is better but slower) +const SIZE = 5.0 // BLUR SIZE (Radius) +const PI = 6.28318530718 // Pi*2 +const OPACITY = 0.21 + + +var Time float +var NoiseOffset float + +func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 { + uv := srcPos + + average := vec3(0.0) + radius := SIZE / 2 + + amount := 0.0 + for d:=0.0; d<PI; d+=PI/DIRECTIONS{ + for i:=1.0/QUALITY; i<=1.0; i+=1.0/QUALITY{ + t := imageSrc0UnsafeAt(uv + vec2(cos(d),sin(d))*radius*log(i)).rgb + + brightness := dot(t.rgb, vec3(0.2126, 0.7152, 0.0722)) + if brightness > THRESHOLD { + average += t + amount += 1.0 + } + } + } + + col := imageSrc0UnsafeAt(uv).rgb + if amount > 0 { + col += (average / amount) * OPACITY + } + + return vec4(col,1.0) +} + diff --git a/shaders/clouds.kage b/shaders/clouds.kage index 26597e5..62a0ae0 100644 --- a/shaders/clouds.kage +++ b/shaders/clouds.kage @@ -13,6 +13,7 @@ const cloudlight = 0.3 const cloudcover = 0.2 const cloudalpha = 8.0 const skytint = 0.5 +const colorDepth = 64 func rand(co vec2) float { return fract(sin(dot(co.xy, vec2(12.9898,-78.233))) * 43758.5453) @@ -59,10 +60,11 @@ func fbm(n vec2) float { func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 { m := mat2(1.6, 1.2, -1.2, 1.6) - skycolour1 := vec3(0.45, 0.57, 0.66) - skycolour2 := vec3(0.55, 0.77, 0.86) + skycolour := vec3(0.68, 0.81, 0.86) + //skycolour2 := vec3(0.55, 0.77, 0.86) + + p := floor(srcPos.xy) / imageSrc0Size().xy; - p := srcPos.xy / imageSrc0Size().xy; uv := p*vec2(imageSrc0Size().x/imageSrc0Size().y,1.0); time := Time * speed q := fbm(uv * cloudscale * 0.5) @@ -120,12 +122,13 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 { c += c1 - skycolour := mix(skycolour2, skycolour1, p.y); + //skycolour := mix(skycolour2, skycolour1, 0); cloudcolour := vec3(1.1, 1.1, 0.9) * clamp((clouddark + cloudlight*c), 0.0, 1.0); f = cloudcover + cloudalpha*f*r; result := mix(skycolour, clamp(skytint * skycolour + cloudcolour, 0.0, 1.0), clamp(f + c, 0.0, 1.0)); + result = floor(result*colorDepth)/colorDepth return vec4( result, 1.0 ); } diff --git a/shaders/none.kage b/shaders/none.kage index 3eccc50..941070d 100644 --- a/shaders/none.kage +++ b/shaders/none.kage @@ -5,8 +5,8 @@ package main var Time float -var Cursor vec2 +var NoiseOffset float func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 { - return imageSrc2UnsafeAt(srcPos); + return imageSrc0UnsafeAt(srcPos) } diff --git a/shaders/vcr_lite.kage b/shaders/vcr_lite.kage new file mode 100644 index 0000000..405195c --- /dev/null +++ b/shaders/vcr_lite.kage @@ -0,0 +1,33 @@ +//go:build ignore + +//kage:unit pixels + +package main + +var Time float +var NoiseOffset float + +const noiseX = 840.0 +const noiseY = 840.0 +const speed = 0.01 + +const colorOffsetIntensity = 0.1 + +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 { + time := Time * speed + 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) + 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) +} |