First day
This commit is contained in:
commit
845a7d3aba
|
@ -0,0 +1 @@
|
|||
build
|
|
@ -0,0 +1,32 @@
|
|||
# Build dependencies
|
||||
GO = tinygo
|
||||
WASM_OPT = wasm-opt
|
||||
|
||||
# Whether to build for debugging instead of release
|
||||
DEBUG = 0
|
||||
|
||||
# Compilation flags
|
||||
GOFLAGS = -target ./target.json -panic trap
|
||||
ifeq ($(DEBUG), 1)
|
||||
GOFLAGS += -opt 1
|
||||
else
|
||||
GOFLAGS += -opt z -no-debug
|
||||
endif
|
||||
|
||||
# wasm-opt flags
|
||||
WASM_OPT_FLAGS = -Oz --zero-filled-memory --strip-producers --enable-bulk-memory
|
||||
|
||||
all:
|
||||
@mkdir -p build
|
||||
$(GO) build $(GOFLAGS) -o build/cart.wasm .
|
||||
ifneq ($(DEBUG), 1)
|
||||
ifeq (, $(shell command -v $(WASM_OPT)))
|
||||
@echo Tip: $(WASM_OPT) was not found. Install it from binaryen for smaller builds!
|
||||
else
|
||||
$(WASM_OPT) $(WASM_OPT_FLAGS) build/cart.wasm -o build/cart.wasm
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf build
|
|
@ -0,0 +1,26 @@
|
|||
# newyearkrendelki
|
||||
|
||||
A game written in Go for the [WASM-4](https://wasm4.org) fantasy console.
|
||||
|
||||
## Building
|
||||
|
||||
Build the cart by running:
|
||||
|
||||
```shell
|
||||
make
|
||||
```
|
||||
|
||||
Then run it with:
|
||||
|
||||
```shell
|
||||
w4 run build/cart.wasm
|
||||
```
|
||||
|
||||
For more info about setting up WASM-4, see the [quickstart guide](https://wasm4.org/docs/getting-started/setup?code-lang=go#quickstart).
|
||||
|
||||
## Links
|
||||
|
||||
- [Documentation](https://wasm4.org/docs): Learn more about WASM-4.
|
||||
- [Snake Tutorial](https://wasm4.org/docs/tutorials/snake/goal): Learn how to build a complete game
|
||||
with a step-by-step tutorial.
|
||||
- [GitHub](https://github.com/aduros/wasm4): Submit an issue or PR. Contributions are welcome!
|
|
@ -0,0 +1,65 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"cart/w4"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
var smiley = [8]byte{
|
||||
0b11000011,
|
||||
0b10000001,
|
||||
0b00100100,
|
||||
0b00100100,
|
||||
0b00000000,
|
||||
0b00100100,
|
||||
0b10011001,
|
||||
0b11000011,
|
||||
}
|
||||
|
||||
var gravity = 0.2
|
||||
var points []*Point = []*Point{}
|
||||
var sticks []*Stick = []*Stick{}
|
||||
var player *Player
|
||||
var frame uint64 = 0
|
||||
var lightIndex uint64 = 0
|
||||
|
||||
//go:export start
|
||||
func start() {
|
||||
rand.Seed(654654321348654)
|
||||
points = []*Point{}
|
||||
sticks = []*Stick{}
|
||||
w4.PALETTE[0] = 0xfcdeea
|
||||
w4.PALETTE[1] = 0x012824
|
||||
w4.PALETTE[2] = 0x265935
|
||||
w4.PALETTE[3] = 0xff4d6d
|
||||
player = &Player{
|
||||
Position: Vector{80, 80},
|
||||
Speed: Vector{},
|
||||
Gamepad: w4.GAMEPAD1,
|
||||
}
|
||||
for i := 0; i < 4; i++ {
|
||||
p, s := CreateRope(
|
||||
Vector{0, rand.Float64()*40 + float64(i*40)},
|
||||
Vector{160, rand.Float64()*40 + float64(i*40)},
|
||||
15,
|
||||
)
|
||||
points = append(points, p...)
|
||||
sticks = append(sticks, s...)
|
||||
}
|
||||
}
|
||||
|
||||
//go:export update
|
||||
func update() {
|
||||
frame += 1
|
||||
*w4.DRAW_COLORS = 2
|
||||
// w4.Text("Hello from Go!", 10, 10)
|
||||
Simulate(points, sticks)
|
||||
for _, s := range sticks {
|
||||
s.Draw()
|
||||
}
|
||||
for _, p := range points {
|
||||
p.Draw()
|
||||
}
|
||||
player.Update()
|
||||
player.Draw()
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package main
|
||||
|
||||
import "cart/w4"
|
||||
|
||||
type Player struct {
|
||||
Position Vector
|
||||
Speed Vector
|
||||
PointGrabbed *Point
|
||||
GrabTimeout uint
|
||||
Offset float64
|
||||
Gamepad *uint8
|
||||
}
|
||||
|
||||
func (p *Player) Update() {
|
||||
p.Speed.X = 0
|
||||
if p.GrabTimeout > 0 {
|
||||
p.GrabTimeout--
|
||||
}
|
||||
if *p.Gamepad&w4.BUTTON_LEFT != 0 {
|
||||
p.Speed.X -= 1
|
||||
}
|
||||
if *p.Gamepad&w4.BUTTON_RIGHT != 0 {
|
||||
p.Speed.X += 1
|
||||
}
|
||||
isJumping := *p.Gamepad&w4.BUTTON_DOWN == 0
|
||||
p.Speed.Y += gravity
|
||||
if p.PointGrabbed != nil {
|
||||
p.Speed.Y = 0
|
||||
p.Position = p.PointGrabbed.Position
|
||||
if *p.Gamepad&w4.BUTTON_2 != 0 {
|
||||
p.GrabTimeout = 10
|
||||
if isJumping {
|
||||
p.GrabTimeout = 5
|
||||
p.Speed.Y = -4.5
|
||||
}
|
||||
p.PointGrabbed = nil
|
||||
}
|
||||
} else {
|
||||
p.Position.Move(p.Speed.X, p.Speed.Y)
|
||||
if *p.Gamepad&w4.BUTTON_DOWN == 0 && p.GrabTimeout == 0 {
|
||||
for _, point := range points {
|
||||
diff := p.Position.Sub(point.Position)
|
||||
if diff.LenSquared() < 25 {
|
||||
// nearPoints = append(nearPoints, p)
|
||||
*w4.DRAW_COLORS = 0x44
|
||||
w4.Rect(int(point.Position.X), int(point.Position.Y), 3, 3)
|
||||
p.PointGrabbed = point
|
||||
point.PreviousPosition.Move(-p.Speed.X*2, -p.Speed.Y*2)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Player) Draw() {
|
||||
*w4.DRAW_COLORS = 0x34
|
||||
w4.Rect(int(p.Position.X)-4, int(p.Position.Y)-4, 8, 8)
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"cart/w4"
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Point struct {
|
||||
Position Vector
|
||||
PreviousPosition Vector
|
||||
IsLocked bool
|
||||
TimeOffset uint64
|
||||
}
|
||||
|
||||
func (p *Point) Draw() {
|
||||
*w4.DRAW_COLORS = 0x31
|
||||
fr := (frame + p.TimeOffset) % 60
|
||||
if fr > 20 {
|
||||
*w4.DRAW_COLORS = 0x32
|
||||
}
|
||||
if fr > 40 {
|
||||
*w4.DRAW_COLORS = 0x34
|
||||
}
|
||||
w4.Oval(int(p.Position.X)-2, int(p.Position.Y)-2, 4, 4)
|
||||
}
|
||||
|
||||
type Stick struct {
|
||||
PointA *Point
|
||||
PointB *Point
|
||||
Length float64
|
||||
}
|
||||
|
||||
func (s *Stick) Draw() {
|
||||
*w4.DRAW_COLORS = 0x3
|
||||
w4.Line(int(s.PointA.Position.X), int(s.PointA.Position.Y),
|
||||
int(s.PointB.Position.X), int(s.PointB.Position.Y))
|
||||
}
|
||||
|
||||
func Simulate(points []*Point, sticks []*Stick) {
|
||||
for _, p := range points {
|
||||
if !p.IsLocked {
|
||||
positionBeforeUpdate := p.Position
|
||||
diff := p.Position.Sub(p.PreviousPosition)
|
||||
p.Position = p.Position.Sum(diff)
|
||||
p.Position.Y += gravity
|
||||
p.PreviousPosition = positionBeforeUpdate
|
||||
}
|
||||
}
|
||||
|
||||
cycles := 20
|
||||
for i := 0; i < cycles; i++ {
|
||||
for _, s := range sticks {
|
||||
centerX := (s.PointA.Position.X + s.PointB.Position.X) / 2
|
||||
centerY := (s.PointA.Position.Y + s.PointB.Position.Y) / 2
|
||||
diff := s.PointA.Position.Sub(s.PointB.Position)
|
||||
direction := diff.Normalized()
|
||||
if !s.PointA.IsLocked {
|
||||
s.PointA.Position.X = centerX + direction.X*s.Length/2
|
||||
s.PointA.Position.Y = centerY + direction.Y*s.Length/2
|
||||
}
|
||||
if !s.PointB.IsLocked {
|
||||
s.PointB.Position.X = centerX - direction.X*s.Length/2
|
||||
s.PointB.Position.Y = centerY - direction.Y*s.Length/2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func CreateRope(start Vector, end Vector, divisions int) ([]*Point, []*Stick) {
|
||||
var points []*Point = []*Point{}
|
||||
var sticks []*Stick = []*Stick{}
|
||||
for i := 0; i <= divisions; i++ {
|
||||
k := float64(i) / float64(divisions)
|
||||
diffX := end.X - start.X
|
||||
diffY := end.Y - start.Y
|
||||
posX := start.X + diffX*k
|
||||
posY := start.Y + diffY*k
|
||||
pos := Vector{posX, posY}
|
||||
// w4.Trace("Point created at " + pos.String())
|
||||
point := Point{
|
||||
Position: pos,
|
||||
PreviousPosition: pos,
|
||||
IsLocked: (i == 0 || i == divisions),
|
||||
TimeOffset: lightIndex * 153,
|
||||
}
|
||||
lightIndex++
|
||||
if i != 0 {
|
||||
lastPoint := points[len(points)-1]
|
||||
diffX := pos.X - lastPoint.Position.X
|
||||
diffY := pos.Y - lastPoint.Position.Y
|
||||
len := math.Sqrt(diffX*diffX + diffY*diffY)
|
||||
w4.Trace("Length between points is " + strconv.FormatFloat(len, 'f', 3, 64))
|
||||
stick := Stick{
|
||||
PointA: lastPoint,
|
||||
PointB: &point,
|
||||
Length: len,
|
||||
}
|
||||
sticks = append(sticks, &stick)
|
||||
}
|
||||
points = append(points, &point)
|
||||
}
|
||||
return points, sticks
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"llvm-target": "wasm32--wasi",
|
||||
"build-tags": [ "tinygo.wasm" ],
|
||||
"goos": "js",
|
||||
"goarch": "wasm",
|
||||
"linker": "wasm-ld",
|
||||
"libc": "wasi-libc",
|
||||
"cflags": [
|
||||
"--target=wasm32--wasi",
|
||||
"--sysroot={root}/lib/wasi-libc/sysroot",
|
||||
"-Oz"
|
||||
],
|
||||
"ldflags": [
|
||||
"--allow-undefined",
|
||||
"--no-demangle",
|
||||
"--import-memory",
|
||||
"--initial-memory=65536",
|
||||
"--max-memory=65536",
|
||||
"--stack-first",
|
||||
"-zstack-size=14752",
|
||||
"--strip-all"
|
||||
],
|
||||
"wasm-abi": "js"
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Vector struct {
|
||||
X float64
|
||||
Y float64
|
||||
}
|
||||
|
||||
func (v *Vector) String() string {
|
||||
return "(" + strconv.FormatFloat(v.X, 'f', 3, 64) + "; " + strconv.FormatFloat(v.Y, 'f', 3, 64) + ")"
|
||||
}
|
||||
|
||||
func (v *Vector) LenSquared() float64 {
|
||||
return v.X*v.X + v.Y*v.Y
|
||||
}
|
||||
|
||||
func (v *Vector) Len() float64 {
|
||||
return math.Sqrt(v.LenSquared())
|
||||
}
|
||||
|
||||
func (v *Vector) Sum(v2 Vector) Vector {
|
||||
return Vector{
|
||||
v.X + v2.X,
|
||||
v.Y + v2.Y,
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Vector) Sub(v2 Vector) Vector {
|
||||
return Vector{
|
||||
v.X - v2.X,
|
||||
v.Y - v2.Y,
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Vector) MulScalar(c float64) Vector {
|
||||
return Vector{
|
||||
v.X * c,
|
||||
v.Y * c,
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Vector) DivScalar(c float64) Vector {
|
||||
return Vector{
|
||||
v.X * c,
|
||||
v.Y * c,
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Vector) Normalized() Vector {
|
||||
len := math.Sqrt(v.X*v.X + v.Y*v.Y)
|
||||
x := v.X / len
|
||||
y := v.Y / len
|
||||
return Vector{x, y}
|
||||
}
|
||||
|
||||
func (v *Vector) Move(x float64, y float64) {
|
||||
v.X += x
|
||||
v.Y += y
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
//
|
||||
// WASM-4: https://wasm4.org/docs
|
||||
|
||||
package w4
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
// │ Platform Constants │
|
||||
// │ │
|
||||
// └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
const SCREEN_SIZE int = 160
|
||||
|
||||
// ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
// │ Memory Addresses │
|
||||
// │ │
|
||||
// └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
var PALETTE = (*[4]uint32)(unsafe.Pointer(uintptr(0x04)))
|
||||
var DRAW_COLORS = (*uint16)(unsafe.Pointer(uintptr(0x14)))
|
||||
var GAMEPAD1 = (*uint8)(unsafe.Pointer(uintptr(0x16)))
|
||||
var GAMEPAD2 = (*uint8)(unsafe.Pointer(uintptr(0x17)))
|
||||
var GAMEPAD3 = (*uint8)(unsafe.Pointer(uintptr(0x18)))
|
||||
var GAMEPAD4 = (*uint8)(unsafe.Pointer(uintptr(0x19)))
|
||||
var MOUSE_X = (*int16)(unsafe.Pointer(uintptr(0x1a)))
|
||||
var MOUSE_Y = (*int16)(unsafe.Pointer(uintptr(0x1c)))
|
||||
var MOUSE_BUTTONS = (*uint8)(unsafe.Pointer(uintptr(0x1e)))
|
||||
var SYSTEM_FLAGS = (*uint8)(unsafe.Pointer(uintptr(0x1f)));
|
||||
var NETPLAY = (*uint8)(unsafe.Pointer(uintptr(0x20)));
|
||||
var FRAMEBUFFER = (*[6400]uint8)(unsafe.Pointer(uintptr(0xa0)))
|
||||
|
||||
const BUTTON_1 byte = 1
|
||||
const BUTTON_2 byte = 2
|
||||
const BUTTON_LEFT byte = 16
|
||||
const BUTTON_RIGHT byte = 32
|
||||
const BUTTON_UP byte = 64
|
||||
const BUTTON_DOWN byte = 128
|
||||
|
||||
const MOUSE_LEFT byte = 1
|
||||
const MOUSE_RIGHT byte = 2
|
||||
const MOUSE_MIDDLE byte = 4
|
||||
|
||||
const SYSTEM_PRESERVE_FRAMEBUFFER byte = 1
|
||||
const SYSTEM_HIDE_GAMEPAD_OVERLAY byte = 2
|
||||
|
||||
// ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
// │ Drawing Functions │
|
||||
// │ │
|
||||
// └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
/** Copies pixels to the framebuffer. */
|
||||
//go:export blit
|
||||
func Blit(sprite *byte, x int, y int, width uint, height uint, flags uint)
|
||||
|
||||
/** Copies a subregion within a larger sprite atlas to the framebuffer. */
|
||||
//go:export blitSub
|
||||
func BlitSub(sprite *byte, x int, y int, width uint, height uint,
|
||||
srcX uint, srcY uint, stride int, flags uint)
|
||||
|
||||
const BLIT_2BPP = 1
|
||||
const BLIT_1BPP = 0
|
||||
const BLIT_FLIP_X = 2
|
||||
const BLIT_FLIP_Y = 4
|
||||
const BLIT_ROTATE = 8
|
||||
|
||||
/** Draws a line between two points. */
|
||||
//go:export line
|
||||
func Line(x1 int, y1 int, x2 int, y2 int)
|
||||
|
||||
/** Draws a horizontal line. */
|
||||
//go:export hline
|
||||
func HLine(x int, y int, len uint)
|
||||
|
||||
/** Draws a vertical line. */
|
||||
//go:export vline
|
||||
func VLine(x int, y int, len uint)
|
||||
|
||||
/** Draws an oval (or circle). */
|
||||
//go:export oval
|
||||
func Oval(x int, y int, width uint, height uint)
|
||||
|
||||
/** Draws a rectangle. */
|
||||
//go:export rect
|
||||
func Rect(x int, y int, width uint, height uint)
|
||||
|
||||
/** Draws text using the built-in system font. */
|
||||
//go:export textUtf8
|
||||
func Text(text string, x int, y int)
|
||||
|
||||
// ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
// │ Sound Functions │
|
||||
// │ │
|
||||
// └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
/** Plays a sound tone. */
|
||||
//go:export tone
|
||||
func Tone(frequency uint, duration uint, volume uint, flags uint)
|
||||
|
||||
const TONE_PULSE1 = 0
|
||||
const TONE_PULSE2 = 1
|
||||
const TONE_TRIANGLE = 2
|
||||
const TONE_NOISE = 3
|
||||
const TONE_MODE1 = 0
|
||||
const TONE_MODE2 = 4
|
||||
const TONE_MODE3 = 8
|
||||
const TONE_MODE4 = 12
|
||||
const TONE_PAN_LEFT = 16
|
||||
const TONE_PAN_RIGHT = 32
|
||||
|
||||
// ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
// │ Storage Functions │
|
||||
// │ │
|
||||
// └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
/** Reads up to `size` bytes from persistent storage into the pointer `destPtr`. */
|
||||
//go:export diskr
|
||||
func DiskR(ptr unsafe.Pointer, count uint) uint
|
||||
|
||||
/** Writes up to `size` bytes from the pointer `srcPtr` into persistent storage. */
|
||||
//go:export diskw
|
||||
func DiskW(src unsafe.Pointer, count uint) uint
|
||||
|
||||
// ┌───────────────────────────────────────────────────────────────────────────┐
|
||||
// │ │
|
||||
// │ Other Functions │
|
||||
// │ │
|
||||
// └───────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
/** Prints a message to the debug console. */
|
||||
//go:export traceUtf8
|
||||
func Trace(str string)
|
||||
|
||||
// TinyGo requires a main function, so provide one
|
||||
//go:linkname main main.main
|
||||
func main() {}
|
Loading…
Reference in New Issue