skulls!
This commit is contained in:
commit
a0ff055379
17 changed files with 937 additions and 0 deletions
79
README.md
Normal file
79
README.md
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
### Skulls is simple Columns-like strategy game developed in Golang with the Ebiten library (for Android)
|
||||||
|
|
||||||
|
|
||||||
|
All development/debugging was done with the <b>gomobile</b> tool and <b>adb</b>.
|
||||||
|
|
||||||
|
|
||||||
|
###### DEVELOPMENT: Local testing environment
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
// Navigate to skulls/ and generate a <code>.apk</code> with skullsgomobile/:
|
||||||
|
gomobile build -target=android github.com/rootVIII/skulls/skullsgomobile
|
||||||
|
|
||||||
|
// Install the newly created .apk into an already running Android Emulator (from Android Studio):
|
||||||
|
adb -s emulator-5554 install skullsgomobile.apk
|
||||||
|
|
||||||
|
// view logging output from the game:
|
||||||
|
adb logcat
|
||||||
|
|
||||||
|
// Note that I use a pixel4 emulator. I have an alias stored in my profile to open it easily via terminal:
|
||||||
|
alias pixel4='$ANDROID_HOME/emulator/emulator -avd "Pixel_4_API_30"'
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
###### PRODUCTION: Build for Android Studio
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
// Navigate to skulls/ and generate a .aar with skullsebitenbind/
|
||||||
|
ebitenmobile bind -target android -javapkg com.solsticenet.skulls -o skulls.aar github.com/rootVIII/skulls/skullsebitenbind
|
||||||
|
|
||||||
|
// Create a new project in Android Studio named SkullsMobile.
|
||||||
|
// Click File, New Module, import .jar/.aar, and locate the newly created skulls.aar file.
|
||||||
|
// Add the following line into dependencies{} within app/build.gradle and then clean the project:
|
||||||
|
compile project(':skulls')
|
||||||
|
|
||||||
|
// Place the following code inside of MainActivity.java:
|
||||||
|
package com.solsticenet.skullsmobile;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import go.Seq;
|
||||||
|
import com.solsticenet.skulls.skullsebitenbind.EbitenView;
|
||||||
|
|
||||||
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
|
Seq.setContext(getApplicationContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
private EbitenView getEbitenView() {
|
||||||
|
return (EbitenView)this.findViewById(R.id.ebitenview);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
this.getEbitenView().suspendGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
this.getEbitenView().resumeGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
This was developed on macOS Big Sur.
|
||||||
|
<hr>
|
||||||
|
<b>Author: rootVIII 2021</b>
|
||||||
|
<br><br>
|
5
assets/background.go
Normal file
5
assets/background.go
Normal file
File diff suppressed because one or more lines are too long
4
assets/beep.go
Normal file
4
assets/beep.go
Normal file
File diff suppressed because one or more lines are too long
4
assets/blueskull.go
Normal file
4
assets/blueskull.go
Normal file
File diff suppressed because one or more lines are too long
4
assets/clear.go
Normal file
4
assets/clear.go
Normal file
File diff suppressed because one or more lines are too long
4
assets/explosion.go
Normal file
4
assets/explosion.go
Normal file
File diff suppressed because one or more lines are too long
4
assets/greenskull.go
Normal file
4
assets/greenskull.go
Normal file
File diff suppressed because one or more lines are too long
5
assets/intro.go
Normal file
5
assets/intro.go
Normal file
File diff suppressed because one or more lines are too long
4
assets/purpleskull.go
Normal file
4
assets/purpleskull.go
Normal file
File diff suppressed because one or more lines are too long
4
assets/radioland.go
Normal file
4
assets/radioland.go
Normal file
File diff suppressed because one or more lines are too long
4
assets/redskull.go
Normal file
4
assets/redskull.go
Normal file
File diff suppressed because one or more lines are too long
4
assets/themesong.go
Normal file
4
assets/themesong.go
Normal file
File diff suppressed because one or more lines are too long
9
go.mod
Normal file
9
go.mod
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
module github.com/rootVIII/skulls
|
||||||
|
|
||||||
|
go 1.16
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff
|
||||||
|
github.com/hajimehoshi/ebiten/v2 v2.0.6
|
||||||
|
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb
|
||||||
|
)
|
67
go.sum
Normal file
67
go.sum
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2 h1:Ac1OEHHkbAZ6EUnJahF0GKcU0FjPc/V8F1DvjhKngFE=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200707082815-5321531c36a2/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||||
|
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8=
|
||||||
|
github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw=
|
||||||
|
github.com/hajimehoshi/bitmapfont/v2 v2.1.0/go.mod h1:2BnYrkTQGThpr/CY6LorYtt/zEPNzvE/ND69CRTaHMs=
|
||||||
|
github.com/hajimehoshi/ebiten/v2 v2.0.6 h1:sHNymgI+q80xasP69oFyrpup6r2qCNsKxqwsGEh6PWE=
|
||||||
|
github.com/hajimehoshi/ebiten/v2 v2.0.6/go.mod h1:uS3OjMW3f2DRDMtWoIF7yMMmrMkv+fZ6pXcwR1pfA0Y=
|
||||||
|
github.com/hajimehoshi/file2byteslice v0.0.0-20200812174855-0e5e8a80490e/go.mod h1:CqqAHp7Dk/AqQiwuhV1yT2334qbA/tFWQW0MD2dGqUE=
|
||||||
|
github.com/hajimehoshi/go-mp3 v0.3.1 h1:pn/SKU1+/rfK8KaZXdGEC2G/KCB2aLRjbTCrwKcokao=
|
||||||
|
github.com/hajimehoshi/go-mp3 v0.3.1/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
|
||||||
|
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||||
|
github.com/hajimehoshi/oto v0.6.8 h1:yRb3EJQ4lAkBgZYheqmdH6Lr77RV9nSWFsK/jwWdTNY=
|
||||||
|
github.com/hajimehoshi/oto v0.6.8/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||||
|
github.com/jakecoffman/cp v1.0.0/go.mod h1:JjY/Fp6d8E1CHnu74gWNnU0+b9VzEdUVPoJxg2PsTQg=
|
||||||
|
github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk=
|
||||||
|
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU=
|
||||||
|
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
|
||||||
|
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk=
|
||||||
|
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
golang.org/x/mobile v0.0.0-20210208171126-f462b3930c8f h1:aEcjdTsycgPqO/caTgnxfR9xwWOltP/21vtJyFztEy0=
|
||||||
|
golang.org/x/mobile v0.0.0-20210208171126-f462b3930c8f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
|
||||||
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM=
|
||||||
|
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/tools v0.0.0-20201009162240-fcf82128ed91/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
715
skulls.go
Normal file
715
skulls.go
Normal file
|
@ -0,0 +1,715 @@
|
||||||
|
package skulls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||||
|
|
||||||
|
// Required for Ebiten.
|
||||||
|
_ "image/jpeg"
|
||||||
|
_ "image/png"
|
||||||
|
|
||||||
|
"github.com/goki/freetype/truetype"
|
||||||
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
|
"github.com/hajimehoshi/ebiten/v2/audio"
|
||||||
|
"github.com/hajimehoshi/ebiten/v2/audio/mp3"
|
||||||
|
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||||
|
"github.com/hajimehoshi/ebiten/v2/text"
|
||||||
|
"github.com/rootVIII/skulls/assets"
|
||||||
|
"golang.org/x/image/font"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
screenW = 640
|
||||||
|
screenH = 960
|
||||||
|
frame = 64
|
||||||
|
rowMax = 22
|
||||||
|
colMax = 15
|
||||||
|
hotspotUpX = 123.0
|
||||||
|
hotspotUpY = 788.0
|
||||||
|
hotspotLeftX = 39.0
|
||||||
|
hotspotLeftY = 862.0
|
||||||
|
hotspotRightX = 210.0
|
||||||
|
hotspotRightY = 865.0
|
||||||
|
hotspotButtonX = 373.0
|
||||||
|
hotspotButtonY = 818.0
|
||||||
|
)
|
||||||
|
|
||||||
|
// Clock is the global game clock.
|
||||||
|
var Clock float64
|
||||||
|
|
||||||
|
// Game controls overall gameplay.
|
||||||
|
type Game struct {
|
||||||
|
background, explosion, intro *ebiten.Image
|
||||||
|
skulls map[string]*ebiten.Image
|
||||||
|
planchette, onDeck []string
|
||||||
|
skullColors []string
|
||||||
|
skullCollector [][]string
|
||||||
|
skullCoords [][][]int
|
||||||
|
empties [][2]int
|
||||||
|
searchHead [2]int
|
||||||
|
beep, clear, track *audio.Player
|
||||||
|
fontFace font.Face
|
||||||
|
green color.Color
|
||||||
|
isMovingL, isMovingR, isMovingU bool
|
||||||
|
havePlanchette, isPlaying bool
|
||||||
|
wonGame, lostGame bool
|
||||||
|
rollCount, moveCount, explosionCount int
|
||||||
|
jumpCount, jumpMax, loseCount int
|
||||||
|
score, level, best, matchMin int
|
||||||
|
}
|
||||||
|
|
||||||
|
/* - - - - - - - - U P D A T E M E T H O D S - - - - - - - - */
|
||||||
|
|
||||||
|
func (g *Game) rollBones() {
|
||||||
|
|
||||||
|
g.planchette = append(g.planchette[len(g.planchette)-1:], g.planchette[:len(g.planchette)-1]...)
|
||||||
|
|
||||||
|
row, col := g.searchHead[0], g.searchHead[1]
|
||||||
|
for _, skull := range g.planchette {
|
||||||
|
g.skullCollector[row][col] = skull
|
||||||
|
row++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) removeCurrentPos() {
|
||||||
|
row, col := g.searchHead[0], g.searchHead[1]
|
||||||
|
for range g.planchette {
|
||||||
|
g.skullCollector[row][col] = ""
|
||||||
|
row++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) shiftPlanchette() {
|
||||||
|
row, col := g.searchHead[0], g.searchHead[1]
|
||||||
|
for _, skull := range g.planchette {
|
||||||
|
g.skullCollector[row][col] = skull
|
||||||
|
row++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) matchSkulls() [][2]int {
|
||||||
|
return append(g.checkCols(), g.checkRows()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) removeEmpties() {
|
||||||
|
for _, coords := range g.empties {
|
||||||
|
g.skullCollector[coords[0]][coords[1]] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) checkRows() [][2]int {
|
||||||
|
|
||||||
|
var matchesIndex = make([][2]int, 0)
|
||||||
|
var matchColor string
|
||||||
|
var matchCount int
|
||||||
|
|
||||||
|
for x := 0; x < len(g.skullCollector[0]); x++ {
|
||||||
|
|
||||||
|
matchColor = ""
|
||||||
|
matchCount = 0
|
||||||
|
|
||||||
|
for y := 0; y < len(g.skullCollector); y++ {
|
||||||
|
if g.skullCollector[y][x] == matchColor {
|
||||||
|
matchCount++
|
||||||
|
} else {
|
||||||
|
matchCount = 0
|
||||||
|
}
|
||||||
|
var last = (y == len(g.skullCollector)-1) || (g.skullCollector[y+1][x] != g.skullCollector[y][x])
|
||||||
|
if matchCount > 2 && last && len(matchColor) > 0 {
|
||||||
|
for index := y - matchCount; index <= y; index++ {
|
||||||
|
matchesIndex = append(matchesIndex, [2]int{index, x})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
matchColor = g.skullCollector[y][x]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchesIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) checkCols() [][2]int {
|
||||||
|
|
||||||
|
var matchesIndex = make([][2]int, 0)
|
||||||
|
var matchColor string
|
||||||
|
var matchCount int
|
||||||
|
|
||||||
|
for ri, row := range g.skullCollector {
|
||||||
|
matchColor = ""
|
||||||
|
matchCount = 0
|
||||||
|
for ci, col := range row {
|
||||||
|
if col == matchColor {
|
||||||
|
matchCount++
|
||||||
|
} else {
|
||||||
|
matchCount = 0
|
||||||
|
}
|
||||||
|
if matchCount > 2 && (ci == len(row)-1 || g.skullCollector[ri][ci+1] != col) && len(matchColor) > 1 {
|
||||||
|
for index := ci - matchCount; index <= ci; index++ {
|
||||||
|
matchesIndex = append(matchesIndex, [2]int{ri, index})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
matchColor = col
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matchesIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) bubbleSortSkulls() {
|
||||||
|
var length = len(g.skullCollector)
|
||||||
|
|
||||||
|
for x := 0; x < len(g.skullCollector[0]); x++ {
|
||||||
|
for {
|
||||||
|
var madeChange = false
|
||||||
|
for y := 0; y < length; y++ {
|
||||||
|
for i := 0; i < length-y-1; i++ {
|
||||||
|
|
||||||
|
if len(g.skullCollector[y][x]) < 1 && len(g.skullCollector[y+1][x]) > 1 {
|
||||||
|
g.skullCollector[y][x], g.skullCollector[y+1][x] = g.skullCollector[y+1][x], g.skullCollector[y][x]
|
||||||
|
madeChange = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !madeChange {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) isValidMove(direction byte) bool {
|
||||||
|
|
||||||
|
row, col := g.searchHead[0], g.searchHead[1]
|
||||||
|
switch direction {
|
||||||
|
|
||||||
|
case 0x4C:
|
||||||
|
if col < 1 || len(g.skullCollector[row][col-1]) > 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case 0x52:
|
||||||
|
if col > 13 || len(g.skullCollector[row][col+1]) > 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case 0x55:
|
||||||
|
if row < 1 || len(g.skullCollector[row-1][col]) > 0 {
|
||||||
|
|
||||||
|
for {
|
||||||
|
var combined = g.matchSkulls()
|
||||||
|
if len(combined) > 0 {
|
||||||
|
g.clear.Play()
|
||||||
|
g.score += len(combined)
|
||||||
|
g.best = g.score
|
||||||
|
g.empties = combined
|
||||||
|
g.explosionCount = 30
|
||||||
|
g.removeEmpties()
|
||||||
|
g.bubbleSortSkulls()
|
||||||
|
g.clear.Rewind()
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g.reset()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g Game) inHotSpot(courseX, courseY float64) bool {
|
||||||
|
|
||||||
|
touchX, touchY := ebiten.TouchPosition(0)
|
||||||
|
|
||||||
|
if float64(touchX) < courseX || float64(touchX) > courseX+frame {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if float64(touchY) < courseY || float64(touchY) > courseY+frame {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g Game) hotspotClickedLeft() bool {
|
||||||
|
return g.inHotSpot(hotspotLeftX, hotspotLeftY)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g Game) hotspotClickedRight() bool {
|
||||||
|
return g.inHotSpot(hotspotRightX, hotspotRightY)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g Game) hotspotClickedUp() bool {
|
||||||
|
return g.inHotSpot(hotspotUpX, hotspotUpY)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g Game) hotspotClickedButton() bool {
|
||||||
|
return g.inHotSpot(hotspotButtonX, hotspotButtonY)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) updatePlanchette() {
|
||||||
|
|
||||||
|
if !g.lostGame && g.hotspotClickedLeft() {
|
||||||
|
g.isMovingL = true
|
||||||
|
g.isMovingR = false
|
||||||
|
g.isMovingU = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !g.lostGame && g.hotspotClickedRight() {
|
||||||
|
g.isMovingR = true
|
||||||
|
g.isMovingL = false
|
||||||
|
g.isMovingU = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.hotspotClickedUp() {
|
||||||
|
g.isMovingR = false
|
||||||
|
g.isMovingL = false
|
||||||
|
g.isMovingU = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.isMovingL && g.moveCount < 1 && g.isValidMove('L') {
|
||||||
|
|
||||||
|
g.removeCurrentPos()
|
||||||
|
|
||||||
|
g.searchHead[1] -= 1
|
||||||
|
g.shiftPlanchette()
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.isMovingR && g.moveCount < 1 && g.isValidMove('R') {
|
||||||
|
|
||||||
|
g.removeCurrentPos()
|
||||||
|
|
||||||
|
g.searchHead[1] += 1
|
||||||
|
g.shiftPlanchette()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g.isMovingU && g.moveCount < 1 || g.jumpCount == 0) && g.isValidMove('U') {
|
||||||
|
|
||||||
|
g.removeCurrentPos()
|
||||||
|
|
||||||
|
g.searchHead[0] -= 1
|
||||||
|
g.shiftPlanchette()
|
||||||
|
}
|
||||||
|
|
||||||
|
if inpututil.IsTouchJustReleased(0) && (g.isMovingL || g.isMovingR || g.isMovingU) {
|
||||||
|
g.isMovingL, g.isMovingR, g.isMovingU = false, false, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.hotspotClickedButton() {
|
||||||
|
if g.rollCount < 1 {
|
||||||
|
g.beep.Play()
|
||||||
|
g.rollBones()
|
||||||
|
g.beep.Rewind()
|
||||||
|
}
|
||||||
|
g.rollCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.isMovingL || g.isMovingR || g.isMovingU {
|
||||||
|
g.moveCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.rollCount > 9 {
|
||||||
|
g.rollCount = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.moveCount > 7 {
|
||||||
|
g.moveCount = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if g.jumpCount > g.jumpMax {
|
||||||
|
g.jumpCount = 0
|
||||||
|
} else {
|
||||||
|
g.jumpCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) spawn() {
|
||||||
|
g.onDeck = nil
|
||||||
|
maxLen := randNo(1, 5)
|
||||||
|
|
||||||
|
for i := 0; i < maxLen; i++ {
|
||||||
|
g.onDeck = append(g.onDeck, g.skullColors[randNo(0, 4)])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) deepCopyPlanchette() {
|
||||||
|
g.planchette = nil
|
||||||
|
g.planchette = append(g.planchette, g.onDeck...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) insertPlanchette() {
|
||||||
|
row, col := 21, 8
|
||||||
|
for i := len(g.planchette) - 1; i >= 0; i-- {
|
||||||
|
if len(g.skullCollector[row][col]) > 0 {
|
||||||
|
g.lostGame = true
|
||||||
|
g.isPlaying = false
|
||||||
|
}
|
||||||
|
g.skullCollector[row][col] = g.planchette[i]
|
||||||
|
row--
|
||||||
|
}
|
||||||
|
|
||||||
|
g.searchHead[0], g.searchHead[1] = row+1, col
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) initSkullCollector() {
|
||||||
|
g.skullCollector = make([][]string, rowMax)
|
||||||
|
for row := 0; row < rowMax; row++ {
|
||||||
|
cols := make([]string, colMax)
|
||||||
|
for col := 0; col < colMax; col++ {
|
||||||
|
cols[col] = ""
|
||||||
|
}
|
||||||
|
g.skullCollector[row] = cols
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) initSkullCoords() {
|
||||||
|
g.skullCoords = make([][][]int, rowMax)
|
||||||
|
|
||||||
|
for outer, y := 0, 60; y < (rowMax+1)*32; outer, y = outer+1, y+32 {
|
||||||
|
g.skullCoords[outer] = make([][]int, colMax)
|
||||||
|
for inner, x := 0, 22; x < colMax*32; inner, x = inner+1, x+32 {
|
||||||
|
g.skullCoords[outer][inner] = make([]int, 2)
|
||||||
|
g.skullCoords[outer][inner] = []int{x, y}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) initPlanchettes() {
|
||||||
|
g.planchette = make([]string, 0)
|
||||||
|
g.onDeck = make([]string, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) reset() {
|
||||||
|
g.havePlanchette = false
|
||||||
|
g.isMovingL = false
|
||||||
|
g.isMovingR = false
|
||||||
|
g.isMovingU = false
|
||||||
|
g.rollCount = 1
|
||||||
|
g.moveCount = 0
|
||||||
|
g.jumpCount = 1
|
||||||
|
|
||||||
|
switch score := g.score; {
|
||||||
|
|
||||||
|
case score > 99999:
|
||||||
|
g.wonGame = true
|
||||||
|
case score > 250:
|
||||||
|
g.level = 7
|
||||||
|
g.jumpMax = 14
|
||||||
|
case score > 100:
|
||||||
|
g.level = 6
|
||||||
|
g.jumpMax = 16
|
||||||
|
case score > 50:
|
||||||
|
g.level = 5
|
||||||
|
g.jumpMax = 18
|
||||||
|
case score > 40:
|
||||||
|
g.level = 4
|
||||||
|
g.jumpMax = 20
|
||||||
|
case score > 30:
|
||||||
|
g.level = 3
|
||||||
|
g.jumpMax = 25
|
||||||
|
case score > 20:
|
||||||
|
g.level = 2
|
||||||
|
g.jumpMax = 30
|
||||||
|
case score > 10:
|
||||||
|
g.level = 1
|
||||||
|
g.jumpMax = 35
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) resetGame() {
|
||||||
|
g.score = 0
|
||||||
|
g.reset()
|
||||||
|
g.loseCount = 300
|
||||||
|
g.lostGame = false
|
||||||
|
g.isPlaying = false
|
||||||
|
g.wonGame = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) checkTrackPlaying() {
|
||||||
|
if !g.track.IsPlaying() {
|
||||||
|
g.track.Rewind()
|
||||||
|
g.track.Play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* - - - - - - - - D R A W M E T H O D S - - - - - - - - */
|
||||||
|
|
||||||
|
func (g Game) drawBackground(screen *ebiten.Image) {
|
||||||
|
opts := &ebiten.DrawImageOptions{}
|
||||||
|
opts.GeoM.Translate(0, 0)
|
||||||
|
screen.DrawImage(g.background, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g Game) drawAllGameText(screen *ebiten.Image) {
|
||||||
|
text.Draw(screen, fmt.Sprintf("%05d", g.score), g.fontFace, 528, 610, g.green)
|
||||||
|
text.Draw(screen, fmt.Sprintf("%05d", g.best), g.fontFace, 528, 788, g.green)
|
||||||
|
text.Draw(screen, fmt.Sprintf("%02d", g.level), g.fontFace, 556, 926, g.green)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g Game) drawOnDeck(screen *ebiten.Image) {
|
||||||
|
var opts *ebiten.DrawImageOptions
|
||||||
|
|
||||||
|
var odY float64
|
||||||
|
|
||||||
|
switch len(g.onDeck) {
|
||||||
|
case 4:
|
||||||
|
odY = 186.00
|
||||||
|
case 3:
|
||||||
|
odY = 209.00
|
||||||
|
case 2:
|
||||||
|
odY = 222.00
|
||||||
|
case 1:
|
||||||
|
odY = 244.00
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, skull := range g.onDeck {
|
||||||
|
opts = &ebiten.DrawImageOptions{}
|
||||||
|
opts.GeoM.Translate(561.00, odY)
|
||||||
|
screen.DrawImage(g.skulls[skull], opts)
|
||||||
|
odY += 32.00
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g Game) drawSkullCollector(screen *ebiten.Image) {
|
||||||
|
|
||||||
|
var opts *ebiten.DrawImageOptions
|
||||||
|
|
||||||
|
for i, row := range g.skullCollector {
|
||||||
|
for j, col := range row {
|
||||||
|
if len(col) > 0 {
|
||||||
|
opts = &ebiten.DrawImageOptions{}
|
||||||
|
opts.GeoM.Translate(float64(g.skullCoords[i][j][0]), float64(g.skullCoords[i][j][1]))
|
||||||
|
screen.DrawImage(g.skulls[col], opts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) drawExplosions(screen *ebiten.Image) {
|
||||||
|
var opts *ebiten.DrawImageOptions
|
||||||
|
var width = frame / 2
|
||||||
|
if g.explosionCount > 0 {
|
||||||
|
for _, coords := range g.empties {
|
||||||
|
opts = &ebiten.DrawImageOptions{}
|
||||||
|
opts.GeoM.Translate(float64(g.skullCoords[coords[0]][coords[1]][0]), float64(g.skullCoords[coords[0]][coords[1]][1]))
|
||||||
|
i := int(Clock/5) % 8
|
||||||
|
sX, sY := i*width, 0
|
||||||
|
screen.DrawImage(g.explosion.SubImage(image.Rect(sX, sY, sX+width, sY+width)).(*ebiten.Image), opts)
|
||||||
|
g.explosionCount--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g Game) drawIntro(screen *ebiten.Image) {
|
||||||
|
opts := &ebiten.DrawImageOptions{}
|
||||||
|
opts.GeoM.Translate(0, 0)
|
||||||
|
screen.DrawImage(g.intro, opts)
|
||||||
|
|
||||||
|
if int(Clock)%50 < 40 {
|
||||||
|
text.Draw(screen, "TOUCH TO BEGIN", g.fontFace, 200, 890, color.White)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) drawLostGame(screen *ebiten.Image) {
|
||||||
|
if g.loseCount > 0 {
|
||||||
|
text.Draw(screen, "Game Over", g.fontFace, 200, 400, color.White)
|
||||||
|
g.loseCount--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g Game) drawWonGame(screen *ebiten.Image) {
|
||||||
|
text.Draw(screen, " You Win ", g.fontFace, 200, 400, color.White)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* - - - - - - - - E B I T E N M E T H O D S - - - - - - - - */
|
||||||
|
|
||||||
|
// Update proceeds the game state every tick (1/60 [s] by default).
|
||||||
|
func (g *Game) Update() error {
|
||||||
|
Clock++
|
||||||
|
|
||||||
|
if g.isPlaying {
|
||||||
|
if !g.havePlanchette {
|
||||||
|
g.deepCopyPlanchette()
|
||||||
|
g.insertPlanchette()
|
||||||
|
g.spawn()
|
||||||
|
g.havePlanchette = true
|
||||||
|
}
|
||||||
|
g.updatePlanchette()
|
||||||
|
} else if g.lostGame && g.loseCount < 1 {
|
||||||
|
g.resetGame()
|
||||||
|
g.initSkullCollector()
|
||||||
|
g.initPlanchettes()
|
||||||
|
g.spawn()
|
||||||
|
} else if g.wonGame {
|
||||||
|
g.isPlaying = false
|
||||||
|
} else {
|
||||||
|
if inpututil.IsTouchJustReleased(0) {
|
||||||
|
g.isPlaying = true
|
||||||
|
Clock = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout takes the outside/window size and returns the (logical) screen size.
|
||||||
|
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||||
|
return screenW, screenH
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the screen every frame (typically 1/60[s] for 60Hz display).
|
||||||
|
func (g *Game) Draw(screen *ebiten.Image) {
|
||||||
|
g.checkTrackPlaying()
|
||||||
|
if g.lostGame {
|
||||||
|
g.drawBackground(screen)
|
||||||
|
g.drawSkullCollector(screen)
|
||||||
|
g.drawAllGameText(screen)
|
||||||
|
g.drawLostGame(screen)
|
||||||
|
} else if g.wonGame {
|
||||||
|
g.drawBackground(screen)
|
||||||
|
g.drawAllGameText(screen)
|
||||||
|
g.drawWonGame(screen)
|
||||||
|
} else if !g.isPlaying {
|
||||||
|
g.drawIntro(screen)
|
||||||
|
} else {
|
||||||
|
g.drawBackground(screen)
|
||||||
|
g.drawOnDeck(screen)
|
||||||
|
g.drawSkullCollector(screen)
|
||||||
|
g.drawExplosions(screen)
|
||||||
|
g.drawAllGameText(screen)
|
||||||
|
}
|
||||||
|
|
||||||
|
ebitenutil.DebugPrint(screen, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
/* - - - - - - - - U T I L I T Y F U N C T I O N S - - - - - - - - */
|
||||||
|
|
||||||
|
func randNo(min, max int) int {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
return rand.Intn(max-min) + min
|
||||||
|
}
|
||||||
|
|
||||||
|
func readRawIMG(asset []byte) (*ebiten.Image, error) {
|
||||||
|
rawIMG, _, err := image.Decode(bytes.NewReader(asset))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newImage := ebiten.NewImageFromImage(rawIMG)
|
||||||
|
return newImage, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readAudio(context *audio.Context, asset []byte) (*audio.Player, error) {
|
||||||
|
mp3Decoded, err := mp3.Decode(context, bytes.NewReader(asset))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
player, err := audio.NewPlayer(context, mp3Decoded)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return player, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play is the entry point to the game.
|
||||||
|
func Play() (*Game, error) {
|
||||||
|
|
||||||
|
audioContext := audio.NewContext(44100)
|
||||||
|
|
||||||
|
radioLand, err := truetype.Parse(assets.RadioLandTTF)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
PNGs := [][]byte{
|
||||||
|
assets.BackgroundPNG,
|
||||||
|
assets.ExplosionPNG,
|
||||||
|
assets.IntroPNG,
|
||||||
|
assets.GreenskullPNG,
|
||||||
|
assets.RedskullPNG,
|
||||||
|
assets.PurpleskullPNG,
|
||||||
|
assets.BlueskullPNG,
|
||||||
|
}
|
||||||
|
|
||||||
|
var images []*ebiten.Image
|
||||||
|
|
||||||
|
for _, png := range PNGs {
|
||||||
|
ebImage, err := readRawIMG(png)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
images = append(images, ebImage)
|
||||||
|
}
|
||||||
|
|
||||||
|
beepSound, err := readAudio(audioContext, assets.BeepMP3)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSound, err := readAudio(audioContext, assets.ClearMP3)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
themeSong, err := readAudio(audioContext, assets.ThemeMP3)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var game = &Game{
|
||||||
|
background: images[0],
|
||||||
|
explosion: images[1],
|
||||||
|
intro: images[2],
|
||||||
|
beep: beepSound,
|
||||||
|
clear: clearSound,
|
||||||
|
track: themeSong,
|
||||||
|
fontFace: truetype.NewFace(radioLand, &truetype.Options{Size: 28, DPI: 72, Hinting: font.HintingFull}),
|
||||||
|
green: color.RGBA{R: 0x7C, G: 0xFC, B: 0x00, A: 0xFF},
|
||||||
|
skullColors: []string{"purple", "blue", "red", "green"},
|
||||||
|
jumpCount: 1,
|
||||||
|
jumpMax: 35,
|
||||||
|
matchMin: 3,
|
||||||
|
loseCount: 300,
|
||||||
|
}
|
||||||
|
|
||||||
|
game.skulls = map[string]*ebiten.Image{
|
||||||
|
"green": images[3],
|
||||||
|
"red": images[4],
|
||||||
|
"purple": images[5],
|
||||||
|
"blue": images[6],
|
||||||
|
}
|
||||||
|
|
||||||
|
game.initSkullCollector()
|
||||||
|
game.initSkullCoords()
|
||||||
|
game.initPlanchettes()
|
||||||
|
|
||||||
|
game.track.SetVolume(.70)
|
||||||
|
game.clear.SetVolume(.50)
|
||||||
|
game.beep.SetVolume(.50)
|
||||||
|
|
||||||
|
// for _, item := range game.skullCollector {
|
||||||
|
// fmt.Printf("%v\n", item)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for _, item := range game.skullCoords {
|
||||||
|
// fmt.Printf("%v\n", item)
|
||||||
|
// }
|
||||||
|
|
||||||
|
game.spawn()
|
||||||
|
|
||||||
|
ebiten.SetWindowSize(screenW, screenH)
|
||||||
|
ebiten.SetWindowTitle("💀")
|
||||||
|
|
||||||
|
if err := ebiten.RunGame(game); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return game, nil
|
||||||
|
}
|
1
skullsgomobile/.gitignore
vendored
Normal file
1
skullsgomobile/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.log
|
20
skullsgomobile/main.go
Normal file
20
skullsgomobile/main.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "image/jpeg"
|
||||||
|
_ "image/png"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/rootVIII/skulls"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
_, err := skulls.Play()
|
||||||
|
if err != nil {
|
||||||
|
logf, _ := os.OpenFile("SKULLS-ERROR.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
log.SetOutput(logf)
|
||||||
|
log.Println("** An error occurred during startup **")
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue