blob: dc1a8ab89fe4afdc46c838561bdfea2e138e2ddf [file] [log] [blame]
package main
import (
"image"
"log"
"math"
"time"
_ "image/png"
"golang.org/x/mobile/app"
"golang.org/x/mobile/asset"
"golang.org/x/mobile/event/paint"
"golang.org/x/mobile/event/size"
"golang.org/x/mobile/event/touch"
"golang.org/x/mobile/exp/f32"
"golang.org/x/mobile/exp/sprite"
"golang.org/x/mobile/exp/sprite/clock"
"golang.org/x/mobile/exp/sprite/glsprite"
"golang.org/x/mobile/gl"
)
var (
startTime = time.Now()
eng = glsprite.Engine()
scene *sprite.Node
cards []*sprite.Node
cardsXY [][]float32
initialCardsXY [][]float32
curCardIndex = -1
lastMouseXY = []float32{-1, -1}
cardWidth = float32(100)
cardHeight = float32(100)
windowSize = []float32{-1, -1}
swipeMoveThreshold = 70
swipeTimeThreshold = .5
swipeStart time.Time
animSpeedScaler = .1
animRotationScaler = .15
)
func main() {
app.Main(func(a app.App) {
var sz size.Event
for e := range a.Events() {
switch e := app.Filter(e).(type) {
case size.Event:
sz = e
windowSize[0] = float32(sz.WidthPx)
windowSize[1] = float32(sz.HeightPx)
case touch.Event:
onTouch(e)
case paint.Event:
onPaint(sz)
a.EndPaint(e)
}
}
})
}
func onTouch(t touch.Event) {
switch t.Type.String() {
case "begin":
for i := len(cards) - 1; i >= 0; i-- {
if t.X >= getCardX(i) &&
t.Y >= getCardY(i) &&
t.X <= cardWidth+getCardX(i) &&
t.Y <= cardHeight+getCardY(i) {
swipeStart = time.Now()
curCardIndex = i
node := getCardNode(i)
node.Arranger = nil
lastMouseXY[0] = t.X
lastMouseXY[1] = t.Y
return
}
}
case "move":
if curCardIndex > -1 {
eng.SetTransform(cards[curCardIndex], f32.Affine{
{cardWidth, 0, getCardX(curCardIndex) + t.X - lastMouseXY[0]},
{0, cardHeight, getCardY(curCardIndex) + t.Y - lastMouseXY[1]},
})
setCardX(curCardIndex, getCardX(curCardIndex)+t.X-lastMouseXY[0])
setCardY(curCardIndex, getCardY(curCardIndex)+t.Y-lastMouseXY[1])
lastMouseXY[0] = t.X
lastMouseXY[1] = t.Y
}
case "end":
if curCardIndex > -1 {
xDiff := getCardX(curCardIndex) - getInitialX(curCardIndex)
yDiff := getCardY(curCardIndex) - getInitialY(curCardIndex)
timeDiff := time.Since(swipeStart).Seconds()
if (math.Abs(float64(xDiff))+math.Abs(float64(yDiff))) >= float64(swipeMoveThreshold) && timeDiff <= float64(swipeTimeThreshold) {
animate(xDiff, yDiff, t)
} else {
eng.SetTransform(cards[curCardIndex], f32.Affine{
{cardWidth, 0, getInitialX(curCardIndex)},
{0, cardHeight, getInitialY(curCardIndex)},
})
setCardX(curCardIndex, getInitialX(curCardIndex))
setCardY(curCardIndex, getInitialY(curCardIndex))
}
}
curCardIndex = -1
}
}
func animate(xDiff float32, yDiff float32, touch touch.Event) {
index := curCardIndex
curCardIndex = -1
node := getCardNode(index)
startTime := -1
node.Arranger = arrangerFunc(func(eng sprite.Engine, node *sprite.Node, t clock.Time) {
if startTime == -1 {
startTime = int(t)
}
moveSpeed := float32(int(t)-startTime) * float32(animSpeedScaler)
x := getCardX(index)
y := getCardY(index)
if math.Abs(float64(xDiff)) > math.Abs(float64(yDiff)) {
if xDiff > 0 {
x = x + moveSpeed
} else {
x = x - moveSpeed
}
} else {
if yDiff > 0 {
y = y + moveSpeed
} else {
y = y - moveSpeed
}
}
setCardX(index, x)
setCardY(index, y)
position := f32.Affine{
{cardWidth, 0, x + cardWidth/2},
{0, cardHeight, y + cardHeight/2},
}
position.Rotate(&position, float32(t)*float32(animRotationScaler))
position.Translate(&position, -.5, -.5)
eng.SetTransform(node, position)
})
}
func onPaint(sz size.Event) {
if scene == nil {
loadScene()
}
gl.ClearColor(1, 1, 1, 1)
gl.Clear(gl.COLOR_BUFFER_BIT)
now := clock.Time(time.Since(startTime) * 60 / time.Second)
eng.Render(scene, now, sz)
}
func newNode() *sprite.Node {
n := &sprite.Node{}
eng.Register(n)
scene.AppendChild(n)
return n
}
func addCard(x float32, y float32, spriteTex sprite.SubTex) {
n := newNode()
eng.SetSubTex(n, spriteTex)
eng.SetTransform(n, f32.Affine{
{cardWidth, 0, x},
{0, cardHeight, y},
})
cards = append(cards, n)
cardsXY = append(cardsXY, []float32{x, y})
initialCardsXY = append(initialCardsXY, []float32{x, y})
}
func getCardX(cardIndex int) float32 {
return cardsXY[cardIndex][0]
}
func setCardX(cardIndex int, newX float32) {
cardsXY[cardIndex][0] = newX
}
func getCardY(cardIndex int) float32 {
return cardsXY[cardIndex][1]
}
func setCardY(cardIndex int, newY float32) {
cardsXY[cardIndex][1] = newY
}
func getCardNode(cardIndex int) *sprite.Node {
return cards[cardIndex]
}
func getInitialX(cardIndex int) float32 {
return initialCardsXY[cardIndex][0]
}
func getInitialY(cardIndex int) float32 {
return initialCardsXY[cardIndex][1]
}
func loadScene() {
cards = make([]*sprite.Node, 0)
cardsXY = make([][]float32, 0)
initialCardsXY = make([][]float32, 0)
texs := loadTextures()
scene = &sprite.Node{}
eng.Register(scene)
eng.SetTransform(scene, f32.Affine{
{1, 0, 0},
{0, 1, 0},
})
for _, v := range texs {
x := windowSize[0]/2 - cardWidth/2
y := windowSize[1]/2 - cardHeight/2
addCard(x, y, v)
}
}
func loadTextures() map[string]sprite.SubTex {
allTexs := make(map[string]sprite.SubTex)
files := []string{"Clubs-2.png", "Clubs-3.png", "Clubs-4.png", "Clubs-5.png", "Clubs-6.png", "Clubs-7.png", "Clubs-8.png",
"Clubs-9.png", "Clubs-10.png", "Clubs-Jack.png", "Clubs-Queen.png", "Clubs-King.png", "Clubs-Ace.png",
"Diamonds-2.png", "Diamonds-3.png", "Diamonds-4.png", "Diamonds-5.png", "Diamonds-6.png", "Diamonds-7.png", "Diamonds-8.png",
"Diamonds-9.png", "Diamonds-10.png", "Diamonds-Jack.png", "Diamonds-Queen.png", "Diamonds-King.png", "Diamonds-Ace.png",
"Spades-2.png", "Spades-3.png", "Spades-4.png", "Spades-5.png", "Spades-6.png", "Spades-7.png", "Spades-8.png",
"Spades-9.png", "Spades-10.png", "Spades-Jack.png", "Spades-Queen.png", "Spades-King.png", "Spades-Ace.png",
"Hearts-2.png", "Hearts-3.png", "Hearts-4.png", "Hearts-5.png", "Hearts-6.png", "Hearts-7.png", "Hearts-8.png",
"Hearts-9.png", "Hearts-10.png", "Hearts-Jack.png", "Hearts-Queen.png", "Hearts-King.png", "Hearts-Ace.png"}
for _, f := range files {
a, err := asset.Open(f)
if err != nil {
log.Fatal(err)
}
defer a.Close()
img, _, err := image.Decode(a)
if err != nil {
log.Fatal(err)
}
t, err := eng.LoadTexture(img)
if err != nil {
log.Fatal(err)
}
allTexs[f] = sprite.SubTex{t, image.Rect(0, 0, 100, 100)}
}
return allTexs
}
type arrangerFunc func(e sprite.Engine, n *sprite.Node, t clock.Time)
func (a arrangerFunc) Arrange(e sprite.Engine, n *sprite.Node, t clock.Time) { a(e, n, t) }