Kasianov Nikolai Alekseevich
5 months ago
18 changed files with 605 additions and 124 deletions
@ -0,0 +1,46 @@ |
|||||||
|
package game |
||||||
|
|
||||||
|
import "strings" |
||||||
|
|
||||||
|
// Plays sound and rewinds the player
|
||||||
|
func (g *Game) PlaySound(soundKey string) { |
||||||
|
if strings.TrimSpace(soundKey) != "" { |
||||||
|
g.AudioPlayers[soundKey].Rewind() |
||||||
|
g.AudioPlayers[soundKey].Play() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (g *Game) SetVolume(volume float64) { |
||||||
|
if volume > 1.0 || volume < 0.0 { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
g.Config.Volume = volume |
||||||
|
for _, player := range g.AudioPlayers { |
||||||
|
player.SetVolume(volume) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (g *Game) IncreaseVolume(volumeDelta float64) { |
||||||
|
for _, player := range g.AudioPlayers { |
||||||
|
volume := player.Volume() + volumeDelta |
||||||
|
if volume > 1.0 || volume < 0.0 { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
player.SetVolume(volume) |
||||||
|
g.Config.Volume = volume |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (g *Game) DecreaseVolume(volumeDelta float64) { |
||||||
|
for _, player := range g.AudioPlayers { |
||||||
|
volume := player.Volume() - volumeDelta |
||||||
|
if volume > 1.0 || volume < 0.0 { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
player.SetVolume(volume) |
||||||
|
g.Config.Volume = volume |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,73 @@ |
|||||||
|
package game |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/hajimehoshi/ebiten/v2" |
||||||
|
"github.com/hajimehoshi/ebiten/v2/inpututil" |
||||||
|
) |
||||||
|
|
||||||
|
type Capybara struct { |
||||||
|
Sprite *Sprite |
||||||
|
} |
||||||
|
|
||||||
|
func NewCapybara(sprite *Sprite) *Capybara { |
||||||
|
return &Capybara{ |
||||||
|
Sprite: sprite, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (c *Capybara) Update() { |
||||||
|
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) || |
||||||
|
len(inpututil.AppendJustPressedTouchIDs(nil)) != 0 { |
||||||
|
c.Sprite.Animation.Squish += 0.5 |
||||||
|
} |
||||||
|
|
||||||
|
// Capybara Animation
|
||||||
|
capyAniData := &c.Sprite.Animation |
||||||
|
if capyAniData.Theta >= 0.03 { |
||||||
|
capyAniData.BounceDirectionFlag = false |
||||||
|
} else if capyAniData.Theta <= -0.03 { |
||||||
|
capyAniData.BounceDirectionFlag = true |
||||||
|
} |
||||||
|
|
||||||
|
if capyAniData.Squish >= 0 { |
||||||
|
capyAniData.Squish -= 0.05 |
||||||
|
} |
||||||
|
|
||||||
|
if capyAniData.BounceDirectionFlag { |
||||||
|
capyAniData.Theta += 0.001 |
||||||
|
} else { |
||||||
|
capyAniData.Theta -= 0.001 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (c *Capybara) Draw(screen *ebiten.Image, level uint32) { |
||||||
|
// Capybara
|
||||||
|
switch level { |
||||||
|
case 1: |
||||||
|
c.Sprite.ChangeImageByName("capybara_1.png") |
||||||
|
case 2: |
||||||
|
c.Sprite.ChangeImageByName("capybara_2.png") |
||||||
|
case 3: |
||||||
|
c.Sprite.ChangeImageByName("capybara_3.png") |
||||||
|
default: |
||||||
|
c.Sprite.ChangeImageByName("capybara_3.png") |
||||||
|
} |
||||||
|
|
||||||
|
op := &ebiten.DrawImageOptions{} |
||||||
|
capybaraBounds := c.Sprite.Img.Bounds() |
||||||
|
scale := float64(screen.Bounds().Dx()) / float64(capybaraBounds.Dx()) / 2.5 |
||||||
|
c.Sprite.Scale = scale |
||||||
|
op.GeoM.Scale( |
||||||
|
scale+c.Sprite.Animation.Squish, |
||||||
|
scale-c.Sprite.Animation.Squish, |
||||||
|
) |
||||||
|
op.GeoM.Rotate(c.Sprite.Animation.Theta) |
||||||
|
|
||||||
|
capyWidth := float64(c.Sprite.RealBounds().Dx()) |
||||||
|
capyHeight := float64(c.Sprite.RealBounds().Dy()) |
||||||
|
c.Sprite.MoveTo(float64(screen.Bounds().Dx()/2)-capyWidth/2, float64(screen.Bounds().Dy()/2)-capyHeight/2) |
||||||
|
|
||||||
|
op.GeoM.Translate(c.Sprite.X, c.Sprite.Y) |
||||||
|
|
||||||
|
screen.DrawImage(c.Sprite.Img, op) |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
package game |
||||||
|
|
||||||
|
// Returns how many points required to be considered of level
|
||||||
|
func pointsForLevel(level uint32) uint64 { |
||||||
|
return 25 * uint64(level*level) |
||||||
|
} |
@ -0,0 +1,258 @@ |
|||||||
|
package game |
||||||
|
|
||||||
|
import ( |
||||||
|
"image" |
||||||
|
"math/rand" |
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten/v2" |
||||||
|
"github.com/hajimehoshi/ebiten/v2/inpututil" |
||||||
|
) |
||||||
|
|
||||||
|
type MandarinRain struct { |
||||||
|
InProgress bool |
||||||
|
MandarinBox *Physical |
||||||
|
Mandarins []*Physical |
||||||
|
Completed bool |
||||||
|
mandarinCount uint16 |
||||||
|
mandarinInitialCount uint16 |
||||||
|
mandarinsInBox uint16 |
||||||
|
boxFull bool |
||||||
|
mandarinCountRange [2]uint16 |
||||||
|
screenBounds image.Rectangle |
||||||
|
} |
||||||
|
|
||||||
|
func NewMandarinRain(from uint16, to uint16) *MandarinRain { |
||||||
|
rain := MandarinRain{} |
||||||
|
rain.screenBounds = WindowBounds() |
||||||
|
rain.InProgress = false |
||||||
|
rain.mandarinInitialCount = uint16(rand.Int31n(int32(to-from)) + int32(from)) |
||||||
|
rain.mandarinCountRange = [2]uint16{from, to} |
||||||
|
rain.mandarinCount = rain.mandarinInitialCount |
||||||
|
rain.mandarinsInBox = 0 |
||||||
|
rain.boxFull = false |
||||||
|
rain.Completed = false |
||||||
|
|
||||||
|
rain.Mandarins = make([]*Physical, rain.mandarinInitialCount) |
||||||
|
for i := 0; i < int(rain.mandarinInitialCount); i++ { |
||||||
|
rain.Mandarins[i] = NewPhysical(NewSpriteFromFile("mandarin_orange.png"), 10.0) |
||||||
|
} |
||||||
|
|
||||||
|
rain.MandarinBox = NewPhysical(NewSpriteFromFile("mandarin_box_empty.png"), 5.5) |
||||||
|
|
||||||
|
return &rain |
||||||
|
} |
||||||
|
|
||||||
|
func (mr *MandarinRain) Run() { |
||||||
|
if mr.InProgress { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
mr.screenBounds = WindowBounds() |
||||||
|
mr.InProgress = true |
||||||
|
|
||||||
|
// Move oranges to random positions on the top of the screen
|
||||||
|
for _, orange := range mr.Mandarins { |
||||||
|
orange.Sprite.MoveTo(float64(rand.Int31n(int32(mr.screenBounds.Bounds().Dx()-orange.Sprite.RealBounds().Dx()))), 10.0) |
||||||
|
} |
||||||
|
|
||||||
|
// Create mandarin box
|
||||||
|
mr.MandarinBox.Sprite.MoveTo( |
||||||
|
float64(rand.Int31n(int32(mr.screenBounds.Bounds().Dx()-mr.MandarinBox.Sprite.RealBounds().Dx()))), |
||||||
|
10.0, |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
func (mr *MandarinRain) Update(game *Game) { |
||||||
|
mr.screenBounds = WindowBounds() |
||||||
|
|
||||||
|
cPosX, cPosY := ebiten.CursorPosition() |
||||||
|
var tPosX int = 0 |
||||||
|
var tPosY int = 0 |
||||||
|
if len(ebiten.AppendTouchIDs(nil)) != 0 { |
||||||
|
tPosX, tPosY = ebiten.TouchPosition(ebiten.AppendTouchIDs(nil)[0]) |
||||||
|
} |
||||||
|
|
||||||
|
// Oranges
|
||||||
|
temp := mr.Mandarins[:0] |
||||||
|
for _, orange := range mr.Mandarins { |
||||||
|
orange.Acceleration.Vx = 0.0 |
||||||
|
orange.Acceleration.Vy = 9.81 / orange.Mass |
||||||
|
|
||||||
|
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) && |
||||||
|
orange.InVicinity(float64(cPosX), float64(cPosY), 75.0) { |
||||||
|
difference := newVec2f( |
||||||
|
(float64(cPosX-orange.Sprite.RealBounds().Dx()/2)-orange.Sprite.X)*4.5, |
||||||
|
(float64(cPosY-orange.Sprite.RealBounds().Dy()/2)-orange.Sprite.Y)*4.5, |
||||||
|
) |
||||||
|
|
||||||
|
orange.Acceleration.Vx = difference.Vx / orange.Mass |
||||||
|
orange.Acceleration.Vy = difference.Vy / orange.Mass |
||||||
|
} else if len(inpututil.AppendJustPressedTouchIDs(nil)) != 0 && |
||||||
|
orange.InVicinity(float64(tPosX), float64(tPosY), 75.0) { |
||||||
|
|
||||||
|
tPosX, tPosY := ebiten.TouchPosition(ebiten.AppendTouchIDs(nil)[0]) |
||||||
|
difference := newVec2f( |
||||||
|
(float64(tPosX-orange.Sprite.RealBounds().Dx()/2)-orange.Sprite.X)*4.5, |
||||||
|
(float64(tPosY-orange.Sprite.RealBounds().Dy()/2)-orange.Sprite.Y)*4.5, |
||||||
|
) |
||||||
|
|
||||||
|
orange.Acceleration.Vx = difference.Vx / orange.Mass |
||||||
|
orange.Acceleration.Vy = difference.Vy / orange.Mass |
||||||
|
} |
||||||
|
|
||||||
|
orange.Velocity.Vx = orange.Velocity.Vx + orange.Acceleration.Vx*0.05 |
||||||
|
orange.Velocity.Vy = orange.Velocity.Vy + orange.Acceleration.Vy*0.05 |
||||||
|
|
||||||
|
oBounds := orange.Sprite.RealBounds() |
||||||
|
oX := orange.Sprite.X |
||||||
|
oY := orange.Sprite.Y |
||||||
|
|
||||||
|
// Constraints
|
||||||
|
// Right
|
||||||
|
if oX+float64(oBounds.Dx()) >= float64(mr.screenBounds.Dx()) { |
||||||
|
orange.Velocity.Vx = -orange.Velocity.Vx * 0.4 |
||||||
|
} |
||||||
|
|
||||||
|
// Left
|
||||||
|
if oX <= 0 { |
||||||
|
orange.Velocity.Vx = -orange.Velocity.Vx * 0.4 |
||||||
|
} |
||||||
|
|
||||||
|
// Up
|
||||||
|
if oY <= 0.0 { |
||||||
|
orange.Velocity.Vy = -orange.Velocity.Vy * 0.4 |
||||||
|
} |
||||||
|
|
||||||
|
// Bottom
|
||||||
|
if oY+float64(oBounds.Dy()) >= float64(mr.screenBounds.Dy()) { |
||||||
|
orange.Velocity.Vx = orange.Velocity.Vx * 0.4 // friction on the floor
|
||||||
|
orange.Velocity.Vy = -orange.Velocity.Vy * 0.4 |
||||||
|
} |
||||||
|
|
||||||
|
orange.Sprite.X += orange.Velocity.Vx |
||||||
|
orange.Sprite.Y += orange.Velocity.Vy |
||||||
|
|
||||||
|
// Move the orange
|
||||||
|
orange.Sprite.MoveTo(orange.Sprite.X, orange.Sprite.Y) |
||||||
|
|
||||||
|
// Check whether it touches mandarin box
|
||||||
|
if orange.InVicinity(mr.MandarinBox.Sprite.X, mr.MandarinBox.Sprite.Y, float64(mr.MandarinBox.Sprite.RealBounds().Dx())) { |
||||||
|
// Yes!
|
||||||
|
mr.mandarinsInBox++ |
||||||
|
mr.mandarinCount-- |
||||||
|
game.PlaySound("orange_put") |
||||||
|
} else { |
||||||
|
// Do not include this orange in the next update (effectively, delete it)
|
||||||
|
temp = append(temp, orange) |
||||||
|
} |
||||||
|
} |
||||||
|
mr.Mandarins = temp |
||||||
|
|
||||||
|
// Orange box
|
||||||
|
mr.MandarinBox.Acceleration.Vx = 0.0 |
||||||
|
mr.MandarinBox.Acceleration.Vy = 9.81 / mr.MandarinBox.Mass |
||||||
|
|
||||||
|
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) && |
||||||
|
mr.MandarinBox.InVicinity(float64(cPosX), float64(cPosY), 75.0) { |
||||||
|
difference := newVec2f( |
||||||
|
(float64(cPosX-mr.MandarinBox.Sprite.RealBounds().Dx()/2)-mr.MandarinBox.Sprite.X)*3.5, |
||||||
|
(float64(cPosY-mr.MandarinBox.Sprite.RealBounds().Dy()/2)-mr.MandarinBox.Sprite.Y)*3.5, |
||||||
|
) |
||||||
|
|
||||||
|
mr.MandarinBox.Acceleration.Vx = difference.Vx / mr.MandarinBox.Mass |
||||||
|
mr.MandarinBox.Acceleration.Vy = difference.Vy / mr.MandarinBox.Mass |
||||||
|
} else if len(inpututil.AppendJustPressedTouchIDs(nil)) != 0 && |
||||||
|
mr.MandarinBox.InVicinity(float64(tPosX), float64(tPosY), 75.0) { |
||||||
|
|
||||||
|
tPosX, tPosY := ebiten.TouchPosition(ebiten.AppendTouchIDs(nil)[0]) |
||||||
|
difference := newVec2f( |
||||||
|
(float64(tPosX-mr.MandarinBox.Sprite.RealBounds().Dx()/2)-mr.MandarinBox.Sprite.X)*3.5, |
||||||
|
(float64(tPosY-mr.MandarinBox.Sprite.RealBounds().Dy()/2)-mr.MandarinBox.Sprite.Y)*3.5, |
||||||
|
) |
||||||
|
|
||||||
|
mr.MandarinBox.Acceleration.Vx = difference.Vx / mr.MandarinBox.Mass |
||||||
|
mr.MandarinBox.Acceleration.Vy = difference.Vy / mr.MandarinBox.Mass |
||||||
|
} |
||||||
|
|
||||||
|
mr.MandarinBox.Velocity.Vx = mr.MandarinBox.Velocity.Vx + mr.MandarinBox.Acceleration.Vx*0.05 |
||||||
|
mr.MandarinBox.Velocity.Vy = mr.MandarinBox.Velocity.Vy + mr.MandarinBox.Acceleration.Vy*0.05 |
||||||
|
|
||||||
|
mBounds := mr.MandarinBox.Sprite.RealBounds() |
||||||
|
mX := mr.MandarinBox.Sprite.X |
||||||
|
mY := mr.MandarinBox.Sprite.Y |
||||||
|
|
||||||
|
// Right
|
||||||
|
if mX+float64(mBounds.Dx()) >= float64(mr.screenBounds.Dx()) { |
||||||
|
mr.MandarinBox.Velocity.Vx = -mr.MandarinBox.Velocity.Vx * 0.3 |
||||||
|
} |
||||||
|
|
||||||
|
// Left
|
||||||
|
if mX <= 0 { |
||||||
|
mr.MandarinBox.Velocity.Vx = -mr.MandarinBox.Velocity.Vx * 0.3 |
||||||
|
} |
||||||
|
|
||||||
|
// Up
|
||||||
|
if mY <= 0.0 { |
||||||
|
mr.MandarinBox.Velocity.Vy = -mr.MandarinBox.Velocity.Vy * 0.3 |
||||||
|
} |
||||||
|
|
||||||
|
// Bottom
|
||||||
|
if mY+float64(mBounds.Dy()) >= float64(mr.screenBounds.Dy()) { |
||||||
|
mr.MandarinBox.Velocity.Vx = mr.MandarinBox.Velocity.Vx * 0.3 // friction on the floor
|
||||||
|
mr.MandarinBox.Velocity.Vy = -mr.MandarinBox.Velocity.Vy * 0.3 |
||||||
|
} |
||||||
|
|
||||||
|
mr.MandarinBox.Sprite.X += mr.MandarinBox.Velocity.Vx |
||||||
|
mr.MandarinBox.Sprite.Y += mr.MandarinBox.Velocity.Vy |
||||||
|
|
||||||
|
// Move box
|
||||||
|
mr.MandarinBox.Sprite.MoveTo(mr.MandarinBox.Sprite.X, mr.MandarinBox.Sprite.Y) |
||||||
|
|
||||||
|
if mr.mandarinsInBox == mr.mandarinInitialCount && !mr.boxFull { |
||||||
|
// All oranges are in a box!
|
||||||
|
mr.boxFull = true |
||||||
|
game.PlaySound("mandarin_box_full") |
||||||
|
} |
||||||
|
|
||||||
|
// If the box is full with mandarines and is near capybara - end mandarin rain and reward with points!
|
||||||
|
if mr.boxFull && mr.MandarinBox.InVicinity( |
||||||
|
game.Capybara.Sprite.X+float64(game.Capybara.Sprite.RealBounds().Dx()/2), |
||||||
|
game.Capybara.Sprite.Y+float64(game.Capybara.Sprite.RealBounds().Dy()/2), |
||||||
|
float64(mr.screenBounds.Dx())/7) { |
||||||
|
// Give a reward and finish this mandarin rain!
|
||||||
|
game.Save.Points += pointsForLevel(game.Save.Level+1) / 5 |
||||||
|
game.PlaySound("mandarin_rain_completed") |
||||||
|
mr.InProgress = false |
||||||
|
mr.Completed = true |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (mr *MandarinRain) Draw(screen *ebiten.Image) { |
||||||
|
if mr.InProgress { |
||||||
|
// Mandarin box
|
||||||
|
if mr.mandarinsInBox < mr.mandarinInitialCount && mr.mandarinsInBox > 0 { |
||||||
|
mr.MandarinBox.Sprite.ChangeImageByName("mandarin_box_not_empty.png") |
||||||
|
} else if mr.mandarinsInBox == mr.mandarinInitialCount { |
||||||
|
mr.MandarinBox.Sprite.ChangeImageByName("mandarin_box_full.png") |
||||||
|
} else { |
||||||
|
mr.MandarinBox.Sprite.ChangeImageByName("mandarin_box_empty.png") |
||||||
|
} |
||||||
|
|
||||||
|
op := &ebiten.DrawImageOptions{} |
||||||
|
scale := float64(screen.Bounds().Dx()) / float64(mr.MandarinBox.Sprite.Img.Bounds().Dx()) / 6.0 |
||||||
|
mr.MandarinBox.Sprite.Scale = scale // Save current scale for proper collision detection
|
||||||
|
op.GeoM.Scale(scale, scale) |
||||||
|
op.GeoM.Translate(mr.MandarinBox.Sprite.X, mr.MandarinBox.Sprite.Y) |
||||||
|
screen.DrawImage(mr.MandarinBox.Sprite.Img, op) |
||||||
|
|
||||||
|
// Oranges
|
||||||
|
for _, orange := range mr.Mandarins { |
||||||
|
op = &ebiten.DrawImageOptions{} |
||||||
|
scale = float64(screen.Bounds().Dx()) / float64(orange.Sprite.Img.Bounds().Dx()) / 11.5 |
||||||
|
orange.Sprite.Scale = scale // Save current scale for proper collision detection
|
||||||
|
op.GeoM.Scale(scale, scale) |
||||||
|
op.GeoM.Translate(orange.Sprite.X, orange.Sprite.Y) |
||||||
|
screen.DrawImage(orange.Sprite.Img, op) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
package game |
||||||
|
|
||||||
|
import "math" |
||||||
|
|
||||||
|
type Vec2f struct { |
||||||
|
Vx float64 |
||||||
|
Vy float64 |
||||||
|
} |
||||||
|
|
||||||
|
func newVec2f(x float64, y float64) Vec2f { |
||||||
|
return Vec2f{ |
||||||
|
Vx: x, |
||||||
|
Vy: y, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
type Physical struct { |
||||||
|
Sprite *Sprite |
||||||
|
Velocity Vec2f |
||||||
|
Acceleration Vec2f |
||||||
|
Mass float64 |
||||||
|
} |
||||||
|
|
||||||
|
func NewPhysical(sprite *Sprite, mass float64) *Physical { |
||||||
|
return &Physical{ |
||||||
|
Sprite: sprite, |
||||||
|
Velocity: newVec2f(0.0, 0.0), |
||||||
|
Acceleration: newVec2f(0.0, 0.0), |
||||||
|
Mass: 10.0, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Returns true if x and y coordinates are in the radius of the physical sprite
|
||||||
|
func (ph *Physical) InVicinity(x float64, y float64, radius float64) bool { |
||||||
|
distance := math.Sqrt( |
||||||
|
math.Pow(ph.Sprite.X-x, 2.0) + math.Pow(ph.Sprite.Y-y, 2.0), |
||||||
|
) |
||||||
|
|
||||||
|
return distance <= radius |
||||||
|
} |
@ -0,0 +1,92 @@ |
|||||||
|
package game |
||||||
|
|
||||||
|
import ( |
||||||
|
"Unbewohnte/capyclick/resources" |
||||||
|
"image" |
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten/v2" |
||||||
|
) |
||||||
|
|
||||||
|
type AnimationData struct { |
||||||
|
Squish float64 |
||||||
|
Theta float64 |
||||||
|
BounceDirectionFlag bool |
||||||
|
} |
||||||
|
|
||||||
|
// Drawable image structure
|
||||||
|
type Sprite struct { |
||||||
|
Img *ebiten.Image |
||||||
|
X float64 |
||||||
|
Y float64 |
||||||
|
Animation AnimationData |
||||||
|
Scale float64 |
||||||
|
Dragged bool |
||||||
|
} |
||||||
|
|
||||||
|
func NewSprite(img image.Image) *Sprite { |
||||||
|
return &Sprite{ |
||||||
|
Img: ebiten.NewImageFromImage(img), |
||||||
|
X: 0.0, |
||||||
|
Y: 0.0, |
||||||
|
Animation: AnimationData{ |
||||||
|
Squish: 0.0, |
||||||
|
Theta: 0.0, |
||||||
|
BounceDirectionFlag: false, |
||||||
|
}, |
||||||
|
Scale: 1.0, |
||||||
|
Dragged: false, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func NewSpriteFromFile(fileName string) *Sprite { |
||||||
|
return NewSprite(resources.ImageFromFile(fileName)) |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Sprite) ChangeImageByName(fileName string) { |
||||||
|
s.Img = ebiten.NewImageFromImage(resources.ImageFromFile(fileName)) |
||||||
|
} |
||||||
|
|
||||||
|
// Returns how big the image is with applied scale factor
|
||||||
|
func (s *Sprite) RealBounds() image.Rectangle { |
||||||
|
bounds := s.Img.Bounds() |
||||||
|
realBounds := image.Rect(0, 0, bounds.Dx()*int(s.Scale), bounds.Dy()*int(s.Scale)) |
||||||
|
return realBounds |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Sprite) IsIn(x int, y int) bool { |
||||||
|
if x >= int(s.X) && x <= (int(s.X)+s.RealBounds().Dx()) && |
||||||
|
y >= int(s.Y) && y <= (int(s.Y)+s.RealBounds().Dy()) { |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// Moves sprite to given positions. Respects window constraints
|
||||||
|
func (s *Sprite) MoveTo(x float64, y float64) { |
||||||
|
s.X = x |
||||||
|
s.Y = y |
||||||
|
screenBounds := WindowBounds() |
||||||
|
|
||||||
|
// Constraints
|
||||||
|
// Right
|
||||||
|
if s.X+float64(s.RealBounds().Dx()) >= float64(screenBounds.Dx()) { |
||||||
|
s.X = float64(screenBounds.Dx()) - float64(s.RealBounds().Dx()) |
||||||
|
} |
||||||
|
|
||||||
|
// Left
|
||||||
|
if s.X <= 0 { |
||||||
|
s.X = 0 |
||||||
|
} |
||||||
|
|
||||||
|
// Up
|
||||||
|
if s.Y <= 0.0 { |
||||||
|
s.Y = 0.0 |
||||||
|
} |
||||||
|
|
||||||
|
// Bottom
|
||||||
|
if s.Y+float64(s.RealBounds().Dy()) >= float64(screenBounds.Dy()) { |
||||||
|
s.Y = float64(screenBounds.Dy()) - float64(s.RealBounds().Dy()) |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
package game |
||||||
|
|
||||||
|
import ( |
||||||
|
"image" |
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten/v2" |
||||||
|
) |
||||||
|
|
||||||
|
func (g *Game) ToggleFullscreen() { |
||||||
|
if ebiten.IsFullscreen() { |
||||||
|
// Turn fullscreen off
|
||||||
|
ebiten.SetFullscreen(false) |
||||||
|
} else { |
||||||
|
// Go fullscreen
|
||||||
|
ebiten.SetFullscreen(true) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (g *Game) SaveWindowGeometry() { |
||||||
|
// Update configuration and save information
|
||||||
|
width, height := ebiten.WindowSize() |
||||||
|
g.Config.WindowSize = [2]int{width, height} |
||||||
|
|
||||||
|
x, y := ebiten.WindowPosition() |
||||||
|
g.Config.LastWindowPosition = [2]int{x, y} |
||||||
|
} |
||||||
|
|
||||||
|
func WindowBounds() image.Rectangle { |
||||||
|
x, y := ebiten.WindowSize() |
||||||
|
return image.Rect(0, 0, x, y) |
||||||
|
} |
Binary file not shown.
After Width: | Height: | Size: 705 B |
After Width: | Height: | Size: 778 B |
Binary file not shown.
After Width: | Height: | Size: 723 B |
After Width: | Height: | Size: 624 B |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue