mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
examples/drag: Add touches (#506)
This commit is contained in:
parent
5677c8a916
commit
252f4430d8
@ -23,6 +23,7 @@ import (
|
|||||||
_ "image/png"
|
_ "image/png"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
"github.com/hajimehoshi/ebiten/ebitenutil"
|
"github.com/hajimehoshi/ebiten/ebitenutil"
|
||||||
@ -30,6 +31,10 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/inpututil"
|
"github.com/hajimehoshi/ebiten/inpututil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
screenWidth = 320
|
screenWidth = 320
|
||||||
screenHeight = 240
|
screenHeight = 240
|
||||||
@ -82,63 +87,104 @@ func (s *Sprite) Draw(screen *ebiten.Image, dx, dy int, alpha float64) {
|
|||||||
screen.DrawImage(s.image, op)
|
screen.DrawImage(s.image, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
type DragPhase int
|
// StrokeSource represents a input device to provide strokes.
|
||||||
|
type StrokeSource interface {
|
||||||
|
Position() (int, int)
|
||||||
|
IsJustReleased() bool
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
// MouseStrokeSource is a StrokeSource implementation of mouse.
|
||||||
DragPhaseNone DragPhase = iota
|
type MouseStrokeSource struct{}
|
||||||
DragPhaseStart
|
|
||||||
DragPhaseDrag
|
|
||||||
DragPhaseEnd
|
|
||||||
)
|
|
||||||
|
|
||||||
// DragState manages the current drag state.
|
func (m *MouseStrokeSource) Position() (int, int) {
|
||||||
type DragState struct {
|
return ebiten.CursorPosition()
|
||||||
phase DragPhase
|
}
|
||||||
|
|
||||||
|
func (m *MouseStrokeSource) IsJustReleased() bool {
|
||||||
|
return inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonLeft)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TouchStrokeSource is a StrokeSource implementation of touch.
|
||||||
|
type TouchStrokeSource struct {
|
||||||
|
ID int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TouchStrokeSource) Position() (int, int) {
|
||||||
|
return ebiten.TouchPosition(t.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TouchStrokeSource) IsJustReleased() bool {
|
||||||
|
return inpututil.IsTouchJustReleased(t.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stroke manages the current drag state by mouse.
|
||||||
|
type Stroke struct {
|
||||||
|
source StrokeSource
|
||||||
|
|
||||||
// initX and initY represents the position when dragging starts.
|
// initX and initY represents the position when dragging starts.
|
||||||
// initX and initY values don't make sense when phase is DragPhaseNone.
|
|
||||||
initX int
|
initX int
|
||||||
initY int
|
initY int
|
||||||
|
|
||||||
// currentX and currentY represents the current position
|
// currentX and currentY represents the current position
|
||||||
// initX and initY values don't make sense when phase is DragPhaseNone.
|
|
||||||
currentX int
|
currentX int
|
||||||
currentY int
|
currentY int
|
||||||
|
|
||||||
|
released bool
|
||||||
|
|
||||||
|
// draggingObject represents a object (sprite in this case)
|
||||||
|
// that is being dragged.
|
||||||
|
draggingObject interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DragState) Update() {
|
func NewStroke(source StrokeSource) *Stroke {
|
||||||
switch d.phase {
|
cx, cy := source.Position()
|
||||||
case DragPhaseNone:
|
return &Stroke{
|
||||||
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
|
source: source,
|
||||||
cx, cy := ebiten.CursorPosition()
|
initX: cx,
|
||||||
d.phase = DragPhaseStart
|
initY: cy,
|
||||||
d.initX = cx
|
currentX: cx,
|
||||||
d.initY = cy
|
currentY: cy,
|
||||||
d.currentX = cx
|
|
||||||
d.currentY = cy
|
|
||||||
}
|
}
|
||||||
case DragPhaseStart:
|
}
|
||||||
d.phase = DragPhaseDrag
|
|
||||||
case DragPhaseDrag:
|
func (s *Stroke) Update() {
|
||||||
x, y := ebiten.CursorPosition()
|
if s.released {
|
||||||
d.currentX = x
|
return
|
||||||
d.currentY = y
|
|
||||||
if inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonLeft) {
|
|
||||||
d.phase = DragPhaseEnd
|
|
||||||
}
|
}
|
||||||
case DragPhaseEnd:
|
if s.source.IsJustReleased() {
|
||||||
d.phase = DragPhaseNone
|
s.released = true
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
x, y := s.source.Position()
|
||||||
|
s.currentX = x
|
||||||
|
s.currentY = y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stroke) IsReleased() bool {
|
||||||
|
return s.released
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stroke) Position() (int, int) {
|
||||||
|
return s.currentX, s.currentY
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stroke) PositionDiff() (int, int) {
|
||||||
|
dx := s.currentX - s.initX
|
||||||
|
dy := s.currentY - s.initY
|
||||||
|
return dx, dy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stroke) DraggingObject() interface{} {
|
||||||
|
return s.draggingObject
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stroke) SetDraggingObject(object interface{}) {
|
||||||
|
s.draggingObject = object
|
||||||
}
|
}
|
||||||
|
|
||||||
type Game struct {
|
type Game struct {
|
||||||
dragState DragState
|
strokes map[*Stroke]struct{}
|
||||||
sprites []*Sprite
|
sprites []*Sprite
|
||||||
|
|
||||||
// draggingSpriteIndex represents the index of the sprites
|
|
||||||
// that is being dragged. If draggingSpriteIndex is -1,
|
|
||||||
// there is not such sprite.
|
|
||||||
draggingSpriteIndex int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var theGame *Game
|
var theGame *Game
|
||||||
@ -173,40 +219,67 @@ func init() {
|
|||||||
|
|
||||||
// Initialize the game.
|
// Initialize the game.
|
||||||
theGame = &Game{
|
theGame = &Game{
|
||||||
|
strokes: map[*Stroke]struct{}{},
|
||||||
sprites: sprites,
|
sprites: sprites,
|
||||||
draggingSpriteIndex: -1,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Game) update(screen *ebiten.Image) error {
|
func (g *Game) spriteAt(x, y int) *Sprite {
|
||||||
g.dragState.Update()
|
|
||||||
switch g.dragState.phase {
|
|
||||||
case DragPhaseStart:
|
|
||||||
if g.draggingSpriteIndex == -1 {
|
|
||||||
// As the sprites are ordered from back to front,
|
// As the sprites are ordered from back to front,
|
||||||
// search the clicked/touched sprite in reverse order.
|
// search the clicked/touched sprite in reverse order.
|
||||||
for i := len(g.sprites) - 1; i >= 0; i-- {
|
for i := len(g.sprites) - 1; i >= 0; i-- {
|
||||||
s := g.sprites[i]
|
s := g.sprites[i]
|
||||||
if s.In(g.dragState.initX, g.dragState.initY) {
|
if s.In(x, y) {
|
||||||
g.draggingSpriteIndex = i
|
return s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) updateStroke(stroke *Stroke) {
|
||||||
|
stroke.Update()
|
||||||
|
if !stroke.IsReleased() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s := stroke.DraggingObject().(*Sprite)
|
||||||
|
if s == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.MoveBy(stroke.PositionDiff())
|
||||||
|
|
||||||
|
index := -1
|
||||||
|
for i, ss := range g.sprites {
|
||||||
|
if ss == s {
|
||||||
|
index = i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
case DragPhaseEnd:
|
|
||||||
if g.draggingSpriteIndex != -1 {
|
|
||||||
dx := g.dragState.currentX - g.dragState.initX
|
|
||||||
dy := g.dragState.currentY - g.dragState.initY
|
|
||||||
g.sprites[g.draggingSpriteIndex].MoveBy(dx, dy)
|
|
||||||
|
|
||||||
// Move the dragged sprite to the front.
|
// Move the dragged sprite to the front.
|
||||||
s := g.sprites[g.draggingSpriteIndex]
|
g.sprites = append(g.sprites[:index], g.sprites[index+1:]...)
|
||||||
g.sprites = append(
|
|
||||||
g.sprites[:g.draggingSpriteIndex],
|
|
||||||
g.sprites[g.draggingSpriteIndex+1:]...)
|
|
||||||
g.sprites = append(g.sprites, s)
|
g.sprites = append(g.sprites, s)
|
||||||
|
|
||||||
g.draggingSpriteIndex = -1
|
stroke.SetDraggingObject(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) update(screen *ebiten.Image) error {
|
||||||
|
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
|
||||||
|
s := NewStroke(&MouseStrokeSource{})
|
||||||
|
s.SetDraggingObject(g.spriteAt(s.Position()))
|
||||||
|
g.strokes[s] = struct{}{}
|
||||||
|
}
|
||||||
|
for _, id := range inpututil.JustPressedTouchIDs() {
|
||||||
|
s := NewStroke(&TouchStrokeSource{id})
|
||||||
|
s.SetDraggingObject(g.spriteAt(s.Position()))
|
||||||
|
g.strokes[s] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for s := range g.strokes {
|
||||||
|
g.updateStroke(s)
|
||||||
|
if s.IsReleased() {
|
||||||
|
delete(g.strokes, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,19 +287,19 @@ func (g *Game) update(screen *ebiten.Image) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, s := range g.sprites {
|
ss := map[*Sprite]*Stroke{}
|
||||||
if i == g.draggingSpriteIndex {
|
for s := range g.strokes {
|
||||||
s.Draw(screen, 0, 0, 0.5)
|
ss[s.DraggingObject().(*Sprite)] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range g.sprites {
|
||||||
|
if stroke, ok := ss[s]; ok {
|
||||||
|
dx, dy := stroke.PositionDiff()
|
||||||
|
s.Draw(screen, dx, dy, 0.5)
|
||||||
} else {
|
} else {
|
||||||
s.Draw(screen, 0, 0, 1)
|
s.Draw(screen, 0, 0, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if g.draggingSpriteIndex != -1 {
|
|
||||||
s := g.sprites[g.draggingSpriteIndex]
|
|
||||||
dx := g.dragState.currentX - g.dragState.initX
|
|
||||||
dy := g.dragState.currentY - g.dragState.initY
|
|
||||||
s.Draw(screen, dx, dy, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
ebitenutil.DebugPrint(screen, "Drag & Drop the sprites!")
|
ebitenutil.DebugPrint(screen, "Drag & Drop the sprites!")
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user