You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
3.9 KiB
162 lines
3.9 KiB
package system |
|
|
|
import ( |
|
_ "image/png" |
|
"time" |
|
|
|
"golang.org/x/image/colornames" |
|
|
|
"code.rocketnine.space/tslocum/citylimits/component" |
|
. "code.rocketnine.space/tslocum/citylimits/ecs" |
|
"code.rocketnine.space/tslocum/citylimits/world" |
|
"code.rocketnine.space/tslocum/gohan" |
|
"github.com/hajimehoshi/ebiten/v2" |
|
) |
|
|
|
const ( |
|
TileWidth = 128 |
|
|
|
logoText = "POWERED BY EBITEN" |
|
logoTextScale = 4.75 |
|
logoTextWidth = 6.0 * float64(len(logoText)) * logoTextScale |
|
logoTime = 144 * 3.5 |
|
|
|
fadeInTime = 144 * 0.75 |
|
) |
|
|
|
type RenderSystem struct { |
|
ScreenW int |
|
ScreenH int |
|
|
|
img *ebiten.Image |
|
op *ebiten.DrawImageOptions |
|
|
|
camScale float64 |
|
|
|
renderer gohan.Entity |
|
} |
|
|
|
func NewRenderSystem() *RenderSystem { |
|
s := &RenderSystem{ |
|
renderer: ECS.NewEntity(), |
|
img: ebiten.NewImage(320, 100), |
|
op: &ebiten.DrawImageOptions{}, |
|
camScale: 1, |
|
ScreenW: 640, |
|
ScreenH: 480, |
|
} |
|
|
|
return s |
|
} |
|
|
|
func (s *RenderSystem) Needs() []gohan.ComponentID { |
|
return []gohan.ComponentID{ |
|
component.PositionComponentID, |
|
component.SpriteComponentID, |
|
} |
|
} |
|
|
|
func (s *RenderSystem) Uses() []gohan.ComponentID { |
|
return nil |
|
} |
|
|
|
func (s *RenderSystem) Update(_ *gohan.Context) error { |
|
return gohan.ErrSystemWithoutUpdate |
|
} |
|
|
|
func (s *RenderSystem) levelCoordinatesToScreen(x, y float64) (float64, float64) { |
|
px, py := world.World.CamX, world.World.CamY |
|
py *= -1 |
|
return ((x - px) * s.camScale), ((y + py) * s.camScale) |
|
} |
|
|
|
// renderSprite renders a sprite on the screen. |
|
func (s *RenderSystem) renderSprite(x float64, y float64, offsetx float64, offsety float64, angle float64, geoScale float64, colorScale float64, alpha float64, hFlip bool, vFlip bool, sprite *ebiten.Image, target *ebiten.Image) int { |
|
if alpha < .01 || colorScale < .01 { |
|
return 0 |
|
} |
|
|
|
xi, yi := world.CartesianToIso(float64(x), float64(y)) |
|
|
|
padding := float64(world.TileSize) * world.World.CamScale |
|
cx, cy := float64(world.World.ScreenW/2), float64(world.World.ScreenH/2) |
|
|
|
// Skip drawing tiles that are out of the screen. |
|
drawX, drawY := world.IsoToScreen(xi, yi) |
|
if drawX+padding < 0 || drawY+padding < 0 || drawX-padding > float64(world.World.ScreenW) || drawY-padding > float64(world.World.ScreenH) { |
|
return 0 |
|
} |
|
|
|
s.op.GeoM.Reset() |
|
|
|
if hFlip { |
|
s.op.GeoM.Scale(-1, 1) |
|
s.op.GeoM.Translate(TileWidth, 0) |
|
} |
|
if vFlip { |
|
s.op.GeoM.Scale(1, -1) |
|
s.op.GeoM.Translate(0, TileWidth) |
|
} |
|
|
|
// Move to current isometric position. |
|
s.op.GeoM.Translate(xi, yi) |
|
// Translate camera position. |
|
s.op.GeoM.Translate(-world.World.CamX, -world.World.CamY) |
|
// Zoom. |
|
s.op.GeoM.Scale(world.World.CamScale, world.World.CamScale) |
|
// Center. |
|
s.op.GeoM.Translate(cx, cy) |
|
|
|
target.DrawImage(sprite, s.op) |
|
|
|
/*s.op.GeoM.Scale(geoScale, geoScale) |
|
// Rotate |
|
s.op.GeoM.Translate(offsetx, offsety) |
|
s.op.GeoM.Rotate(angle) |
|
// Move to current isometric position. |
|
s.op.GeoM.Translate(x, y) |
|
// Translate camera position. |
|
s.op.GeoM.Translate(-world.World.CamX, -world.World.CamY) |
|
// Zoom. |
|
s.op.GeoM.Scale(s.camScale, s.camScale) |
|
// Center. |
|
//s.op.GeoM.Translate(float64(s.ScreenW/2.0), float64(s.ScreenH/2.0)) |
|
|
|
s.op.ColorM.Scale(colorScale, colorScale, colorScale, alpha) |
|
|
|
target.DrawImage(sprite, s.op) |
|
|
|
s.op.ColorM.Reset()*/ |
|
|
|
return 1 |
|
} |
|
|
|
func (s *RenderSystem) Draw(ctx *gohan.Context, screen *ebiten.Image) error { |
|
if !world.World.GameStarted { |
|
// TODO |
|
if ctx.Entity == world.World.Player { |
|
screen.Fill(colornames.Purple) |
|
} |
|
return nil |
|
} |
|
|
|
position := component.Position(ctx) |
|
sprite := component.Sprite(ctx) |
|
|
|
if sprite.NumFrames > 0 && time.Since(sprite.LastFrame) > sprite.FrameTime { |
|
sprite.Frame++ |
|
if sprite.Frame >= sprite.NumFrames { |
|
sprite.Frame = 0 |
|
} |
|
sprite.Image = sprite.Frames[sprite.Frame] |
|
sprite.LastFrame = time.Now() |
|
} |
|
|
|
colorScale := 1.0 |
|
if sprite.OverrideColorScale { |
|
colorScale = sprite.ColorScale |
|
} |
|
|
|
s.renderSprite(position.X, position.Y, 0, 0, sprite.Angle, 1.0, colorScale, 1.0, sprite.HorizontalFlip, sprite.VerticalFlip, sprite.Image, screen) |
|
return nil |
|
}
|
|
|