summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.go146
-rw-r--r--player.go52
-rw-r--r--shaders/none.kage12
-rw-r--r--shaders/vcr.kage44
-rw-r--r--tilemap.go12
5 files changed, 149 insertions, 117 deletions
diff --git a/main.go b/main.go
index d518abc..7c4e014 100644
--- a/main.go
+++ b/main.go
@@ -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);
+ }
+
+}
diff --git a/tilemap.go b/tilemap.go
index b24bdb6..0bdb401 100644
--- a/tilemap.go
+++ b/tilemap.go
@@ -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)
}