Initial commit
This commit is contained in:
commit
b3f3a77fc7
8 changed files with 242 additions and 0 deletions
14
go.mod
Normal file
14
go.mod
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
module github.com/ChaoticByte/xels
|
||||||
|
|
||||||
|
go 1.24.5
|
||||||
|
|
||||||
|
require github.com/hajimehoshi/ebiten/v2 v2.8.8
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 // indirect
|
||||||
|
github.com/ebitengine/hideconsole v1.0.0 // indirect
|
||||||
|
github.com/ebitengine/purego v0.8.0 // indirect
|
||||||
|
github.com/jezek/xgb v1.1.1 // indirect
|
||||||
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
|
golang.org/x/sys v0.25.0 // indirect
|
||||||
|
)
|
16
go.sum
Normal file
16
go.sum
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 h1:Gk1XUEttOk0/hb6Tq3WkmutWa0ZLhNn/6fc6XZpM7tM=
|
||||||
|
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325/go.mod h1:ulhSQcbPioQrallSuIzF8l1NKQoD7xmMZc5NxzibUMY=
|
||||||
|
github.com/ebitengine/hideconsole v1.0.0 h1:5J4U0kXF+pv/DhiXt5/lTz0eO5ogJ1iXb8Yj1yReDqE=
|
||||||
|
github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A=
|
||||||
|
github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE=
|
||||||
|
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||||
|
github.com/hajimehoshi/ebiten/v2 v2.8.8 h1:xyMxOAn52T1tQ+j3vdieZ7auDBOXmvjUprSrxaIbsi8=
|
||||||
|
github.com/hajimehoshi/ebiten/v2 v2.8.8/go.mod h1:durJ05+OYnio9b8q0sEtOgaNeBEQG7Yr7lRviAciYbs=
|
||||||
|
github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4=
|
||||||
|
github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
|
||||||
|
golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw=
|
||||||
|
golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM=
|
||||||
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||||
|
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
57
main.go
Normal file
57
main.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
|
|
||||||
|
"github.com/ChaoticByte/xels/simulation"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type Application struct {
|
||||||
|
simulation simulation.Simulation
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Application) Update() error {
|
||||||
|
a.simulation.Update()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Application) Draw(screen *ebiten.Image) {
|
||||||
|
// create image from xel grid
|
||||||
|
pixels := make([]byte, 4 * screen.Bounds().Dx() * screen.Bounds().Dy())
|
||||||
|
for i := range len(a.simulation.Grid.Xels) {
|
||||||
|
xel := a.simulation.Grid.Xels[i]
|
||||||
|
var v byte = 0
|
||||||
|
if xel.Energy > 0 {
|
||||||
|
v = byte(max(0, min(255, xel.Energy * 2 + 38)))
|
||||||
|
}
|
||||||
|
// r
|
||||||
|
pixels[i * 4] = v
|
||||||
|
// g
|
||||||
|
pixels[(i*4) + 1] = v
|
||||||
|
// b
|
||||||
|
pixels[(i*4) + 2] = v
|
||||||
|
// a
|
||||||
|
pixels[(i*4) + 3] = 255
|
||||||
|
}
|
||||||
|
screen.WritePixels(pixels)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Application) Layout(outsideWidth int, outsideHeight int) (int, int) {
|
||||||
|
return CanvasWidth, CanvasHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ebiten.SetWindowSize(CanvasWidth, CanvasHeight)
|
||||||
|
ebiten.SetWindowTitle("Pixels - Main Window")
|
||||||
|
ebiten.SetWindowResizingMode(ebiten.WindowResizingModeEnabled)
|
||||||
|
ebiten.MaximizeWindow()
|
||||||
|
ebiten.SetTPS(MaxTps)
|
||||||
|
app := &Application{
|
||||||
|
simulation: *simulation.NewSimulation(CanvasWidth, CanvasHeight),
|
||||||
|
}
|
||||||
|
InitGrid(app.simulation.Grid)
|
||||||
|
err := ebiten.RunGame(app)
|
||||||
|
if err != nil { panic(err) }
|
||||||
|
}
|
12
settings.go
Normal file
12
settings.go
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/ChaoticByte/xels/simulation"
|
||||||
|
|
||||||
|
const CanvasWidth = 200
|
||||||
|
const CanvasHeight = 200
|
||||||
|
const MaxTps = 1000
|
||||||
|
const SimStepsPerUpdate = 10
|
||||||
|
|
||||||
|
func InitGrid(grid *simulation.XelGrid) {
|
||||||
|
grid.GetXel(grid.GetCenterPosition()).Energy = 50000
|
||||||
|
}
|
32
simulation/simulation.go
Normal file
32
simulation/simulation.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package simulation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Simulation struct {
|
||||||
|
Grid *XelGrid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sim *Simulation) Update() {
|
||||||
|
for range 10 {
|
||||||
|
// get all available xels with energy != 0
|
||||||
|
available_positions := []Vector2{}
|
||||||
|
for i, xel := range sim.Grid.Xels {
|
||||||
|
if xel.Energy != 0 {
|
||||||
|
available_positions = append(available_positions, Vector2{X: i % sim.Grid.Width, Y: i/sim.Grid.Height})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// choose random pos
|
||||||
|
pos := available_positions[rand.IntN(len(available_positions))]
|
||||||
|
xel := sim.Grid.GetXel(pos)
|
||||||
|
if xel.Energy == 0 { panic("xel energy null") }
|
||||||
|
xel.Step(pos, sim.Grid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSimulation(width int, height int) *Simulation {
|
||||||
|
return &Simulation{
|
||||||
|
Grid: NewXelGrid(width, height),
|
||||||
|
}
|
||||||
|
}
|
6
simulation/vec2.go
Normal file
6
simulation/vec2.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package simulation
|
||||||
|
|
||||||
|
type Vector2 struct {
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
}
|
69
simulation/xel.go
Normal file
69
simulation/xel.go
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
package simulation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TurnNorth int = iota
|
||||||
|
TurnEast
|
||||||
|
TurnSouth
|
||||||
|
TurnWest
|
||||||
|
)
|
||||||
|
|
||||||
|
type Xel struct {
|
||||||
|
Energy int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (xel *Xel) Step(ownPos Vector2, grid *XelGrid) {
|
||||||
|
// get other xel
|
||||||
|
var otherXelPos Vector2
|
||||||
|
switch rand.IntN(4) {
|
||||||
|
case 0:
|
||||||
|
otherXelPos = Vector2{X: ownPos.X + 1, Y: ownPos.Y}
|
||||||
|
case 1:
|
||||||
|
otherXelPos = Vector2{X: ownPos.X - 1, Y: ownPos.Y}
|
||||||
|
case 2:
|
||||||
|
otherXelPos = Vector2{X: ownPos.X, Y: ownPos.Y + 1}
|
||||||
|
case 3:
|
||||||
|
otherXelPos = Vector2{X: ownPos.X, Y: ownPos.Y - 1}
|
||||||
|
}
|
||||||
|
otherXel := grid.GetXel(otherXelPos)
|
||||||
|
if otherXel == nil { return }
|
||||||
|
// interact
|
||||||
|
if (xel.Energy > 0 && otherXel.Energy > 0) || (xel.Energy < 0 && otherXel.Energy < 0) {
|
||||||
|
if rand.IntN(4) == 0 {
|
||||||
|
// create a higher energy xel and an inverted xel
|
||||||
|
xel.Energy += (2 * otherXel.Energy)
|
||||||
|
otherXel.Energy *= -1
|
||||||
|
} else {
|
||||||
|
xel.Energy += otherXel.Energy
|
||||||
|
otherXel.Energy = 0
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (xel.Energy < 0 && otherXel.Energy > 0) || (xel.Energy > 0 && otherXel.Energy < 0) {
|
||||||
|
// cancel out
|
||||||
|
xel.Energy += otherXel.Energy
|
||||||
|
otherXel.Energy = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (xel.Energy == 0 && otherXel.Energy != 0) || (xel.Energy != 0 && otherXel.Energy == 0) {
|
||||||
|
if xel.Energy > 1 || xel.Energy < -1 || otherXel.Energy > 1 || otherXel.Energy < -1 { // prevent integer 1 / 0
|
||||||
|
// split
|
||||||
|
splitE := (xel.Energy + otherXel.Energy) / 2
|
||||||
|
xel.Energy = splitE + ((xel.Energy + otherXel.Energy) % 2)
|
||||||
|
otherXel.Energy = splitE
|
||||||
|
} else {
|
||||||
|
// move
|
||||||
|
if xel.Energy != 0 {
|
||||||
|
otherXel.Energy = xel.Energy
|
||||||
|
xel.Energy = 0
|
||||||
|
} else {
|
||||||
|
xel.Energy = otherXel.Energy
|
||||||
|
otherXel.Energy = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
36
simulation/xelgrid.go
Normal file
36
simulation/xelgrid.go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package simulation
|
||||||
|
|
||||||
|
type XelGrid struct {
|
||||||
|
Width int // do not overwrite this value after init!
|
||||||
|
Height int // do not overwrite this value after init!
|
||||||
|
Xels []*Xel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (grid *XelGrid) GetCenterPosition() Vector2 { // just a helper
|
||||||
|
return Vector2{
|
||||||
|
X: (grid.Width / 2) + (grid.Width % 2),
|
||||||
|
Y: (grid.Height / 2) + (grid.Height % 2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (grid *XelGrid) GetXel(pos Vector2) *Xel {
|
||||||
|
if pos.X < 0 || pos.X >= grid.Width || pos.Y < 0 || pos.Y >= grid.Height {
|
||||||
|
return nil // out of bounds
|
||||||
|
}
|
||||||
|
i := (pos.Y * grid.Width) + pos.X
|
||||||
|
return grid.Xels[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewXelGrid(width int, height int) *XelGrid {
|
||||||
|
grid := &XelGrid{
|
||||||
|
Width: width,
|
||||||
|
Height: height,
|
||||||
|
Xels: make([]*Xel, width*height),
|
||||||
|
}
|
||||||
|
// init
|
||||||
|
for i := range len(grid.Xels) {
|
||||||
|
grid.Xels[i] = &Xel{}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
return grid
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue