twitchapon-anim

Basic Twitchapon Receiver/Visuals
git clone git://bsandro.tech/twitchapon-anim
Log | Files | Refs | README | LICENSE

ebitest.go (4780B)


      1 package main
      2 
      3 import (
      4 	_ "bytes"
      5 	"errors"
      6 	"fmt"
      7 	"github.com/hajimehoshi/ebiten/v2"
      8 	"github.com/hajimehoshi/ebiten/v2/ebitenutil"
      9 	"image/color"
     10 	_ "image/jpeg"
     11 	_ "image/png"
     12 	"io"
     13 	"log"
     14 	"math"
     15 	"math/rand"
     16 	"net/http"
     17 	"os"
     18 	"strconv"
     19 	"time"
     20 )
     21 
     22 const S_FRAMERATE = 60
     23 const S_SPEED = 200.0
     24 const S_TTL = 20
     25 
     26 var has_req bool = false
     27 
     28 var NumSprites int = 1
     29 var ScreenSize struct {
     30 	width, height int
     31 }
     32 
     33 // images initialized in init()
     34 var Images = make(map[string]*ebiten.Image)
     35 
     36 type Sprite struct {
     37 	img      *ebiten.Image
     38 	opt      ebiten.DrawImageOptions
     39 	x, y     float64
     40 	angle    float64
     41 	rotation float64
     42 	expires  int64
     43 }
     44 
     45 type Game struct {
     46 	inited    bool
     47 	sprites   []*Sprite
     48 	animation *TGifObject
     49 }
     50 
     51 var game *Game
     52 
     53 func (g *Game) Update() error {
     54 	if !g.inited {
     55 		fmt.Println("(Game::update()) calling Game::init()")
     56 		g.init()
     57 	}
     58 
     59 	if ebiten.IsKeyPressed(ebiten.KeyQ) || ebiten.IsKeyPressed(ebiten.KeyEscape) {
     60 		// @todo find out if it is possible to gracefully stop the game via ebiten structure
     61 		return errors.New("exit")
     62 	}
     63 
     64 	if ebiten.IsKeyPressed(ebiten.KeySpace) || has_req {
     65 		g.sprites = append(g.sprites, makeRandomSprite())
     66 		has_req = false
     67 	}
     68 
     69 	sprites_new := []*Sprite{}
     70 	for _, sprite := range g.sprites {
     71 		if sprite.expires > time.Now().Unix() {
     72 			sprites_new = append(sprites_new, sprite)
     73 		}
     74 	}
     75 
     76 	g.sprites = sprites_new
     77 	for _, sprite := range g.sprites {
     78 		err := sprite.Update()
     79 		if err != nil {
     80 			return err
     81 		}
     82 	}
     83 
     84 	_ = g.animation.Update()
     85 
     86 	return nil
     87 }
     88 
     89 func (sprite *Sprite) Update() error {
     90 	wInt, hInt := sprite.img.Size()
     91 	w, h := float64(wInt), float64(hInt)
     92 	fps := ebiten.CurrentFPS()
     93 	if fps == 0 {
     94 		fps = S_FRAMERATE
     95 	}
     96 
     97 	delta := S_SPEED / fps
     98 	dx := delta * math.Cos(sprite.angle)
     99 	dy := delta * math.Sin(sprite.angle)
    100 
    101 	x := sprite.x + dx
    102 	y := sprite.y + dy
    103 
    104 	scrW, scrH := float64(ScreenSize.width), float64(ScreenSize.height)
    105 
    106 	bounce := false
    107 	// bouncing off walls
    108 	if x+w >= scrW || x <= 0 {
    109 		sprite.angle = math.Pi*3 - sprite.angle
    110 		bounce = true
    111 	} else if y+h >= scrH || y <= 0 {
    112 		sprite.angle = math.Pi*2 - sprite.angle
    113 		bounce = true
    114 	}
    115 
    116 	if bounce {
    117 		dx = delta * math.Cos(sprite.angle)
    118 		dy = delta * math.Sin(sprite.angle)
    119 		x = sprite.x + dx
    120 		y = sprite.y + dy
    121 
    122 		if x+w >= scrW || x <= 0 {
    123 			sprite.x -= dx
    124 		}
    125 		if y+h >= scrH || y <= 0 {
    126 			sprite.y -= dy
    127 		}
    128 
    129 	} else {
    130 		sprite.x = x
    131 		sprite.y = y
    132 	}
    133 
    134 	// rotating image
    135 	sprite.rotation += math.Pi / 60.0
    136 
    137 	return nil
    138 }
    139 
    140 func (g *Game) Draw(screen *ebiten.Image) {
    141 	//defer g.ShowDebug(screen)
    142 
    143 	// background
    144 	screen.Fill(color.RGBA{0, 0xFF, 0, 0xFF})
    145 
    146 	for _, sprite := range g.sprites {
    147 		w, h := sprite.img.Size()
    148 		sprite.opt.GeoM.Reset()
    149 		sprite.opt.GeoM.Translate(-float64(w)/2, -float64(h)/2)
    150 		sprite.opt.GeoM.Rotate(sprite.rotation)
    151 		sprite.opt.GeoM.Translate(float64(w/2), float64(h/2))
    152 		sprite.opt.GeoM.Translate(sprite.x, sprite.y)
    153 		//sprite.opt.ColorM.Translate(0, 0, 0, -0.0003)
    154 		screen.DrawImage(sprite.img, &sprite.opt)
    155 	}
    156 
    157 	g.animation.Draw(screen)
    158 }
    159 
    160 func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
    161 	return ScreenSize.width, ScreenSize.height
    162 }
    163 
    164 func (g *Game) init() {
    165 	defer func() {
    166 		g.inited = true
    167 		fmt.Println("Game inited ok")
    168 	}()
    169 	fmt.Println("Game::init()")
    170 	rand.Seed(time.Now().UnixNano())
    171 
    172 	for i := 0; i < NumSprites; i++ {
    173 		g.sprites = append(g.sprites, makeRandomSprite())
    174 	}
    175 
    176 	var err error
    177 	g.animation, err = MakeGifObject("assets/terry1.gif")
    178 	if err != nil {
    179 		log.Fatal(err)
    180 	}
    181 }
    182 
    183 func makeRandomSprite() *Sprite {
    184 	x := float64(ScreenSize.width) / 2.0
    185 	y := float64(ScreenSize.height) / 2.0
    186 	angle := rand.Float64() * math.Pi * 2.0
    187 	fmt.Printf("initial x, y, angle: %0.2f %0.2f %0.2f\n", x, y, angle)
    188 	return makeSprite("chikaiKnife.png", x, y, angle)
    189 }
    190 
    191 func main() {
    192 	if len(os.Args) > 1 {
    193 		NumSprites, _ = strconv.Atoi(os.Args[1])
    194 	}
    195 
    196 	game = &Game{}
    197 	ebiten.SetWindowSize(ScreenSize.width, ScreenSize.height)
    198 	ebiten.SetWindowTitle("Twitchapon Receiver Module")
    199 	ebiten.SetMaxTPS(S_FRAMERATE)
    200 	ebiten.SetRunnableOnUnfocused(true)
    201 
    202 	http.HandleFunc("/", handleHttpRequest)
    203 	go func() {
    204 		http.ListenAndServe("localhost:2345", nil)
    205 	}()
    206 
    207 	if err := ebiten.RunGame(game); err != nil {
    208 		log.Fatal(err)
    209 	}
    210 }
    211 
    212 func makeSprite(name string, x float64, y float64, angle float64) *Sprite {
    213 	return &Sprite{Images[name], ebiten.DrawImageOptions{}, x, y, angle, 0.0 /* rotation */, time.Now().Unix() + S_TTL /* expires */}
    214 }
    215 
    216 func (g *Game) ShowDebug(screen *ebiten.Image) {
    217 	msg := fmt.Sprintf("TPS: %0.2f\nFPS: %0.2f", ebiten.CurrentTPS(), ebiten.CurrentFPS())
    218 	ebitenutil.DebugPrint(screen, msg)
    219 }
    220 
    221 func handleHttpRequest(w http.ResponseWriter, req *http.Request) {
    222 	io.WriteString(w, "OK\n")
    223 	fmt.Println("http request ok")
    224 	has_req = true
    225 }