engoengine / engo Goto Github PK
View Code? Open in Web Editor NEWEngo is an open-source 2D game engine written in Go.
Home Page: https://engoengine.github.io
License: MIT License
Engo is an open-source 2D game engine written in Go.
Home Page: https://engoengine.github.io
License: MIT License
The system.World
variable is being set after the system.New()
function is being called.
As such, one does not have access to the World
from the system.New()
function (null-reference). This should be fixed by simply switching two lines: first calling SetWorld
, then calling New()
.
The Camera API does not correctly stay within bounds. It does not use the limits correctly (those defined in WorldBounds
).
This should be fixed somewhere in assets.go
and batch.go
.
I have no clue how to handle this (SO).
While we are looking at different platforms to support in #63, I feel it would be good to open up discussion about what to do with the old GopherJS backed JavaScript/HTML
backend.
I'm not quite sure how much work it would take to get the GopherJS backend working again. I suspect the hardest thing to do would be fixing up shaders and Font loading/rendering.
(before it even compiles; will be adding more as needed)
loadImage()
loadJSON()
image.NRGBA
into something we can use (i.e. what the hud
demo does to create the green and purple layers)window.GetSize()
window.GetCursorPos()
Does this game engine support sprite maps?
I would like to write a Galaxian game to learn this game engine and I found the following one big PNG file for a game:
This issue is two-fold:
DoesExist
function from the Entitiy
s;Hidden
PriorityLevel
to system.go
, with a negative value (lower than Background
); this will allow objects to not be rendered by RenderSystem
. This can be set by the user in the RenderComponent
the user adds.It's open for anyone who wants to do this.
Removing something from the RenderSystem
, does not remove it visually.
Asked SO to help - wouldn't know where to begin.
How should clicks be handled according to the ECS?
In javascript
/html
, there's some kind of propagation: the foremost element is clicked, then passed along to any other element that may have been involved ; and each time the element has the ability to stop the propagation.
In ECS, I would assume there is some kind of System
that monitors whether or not something gets clicked?
Any best-practices here? Anything I misunderstood? (I imagine the "buttons" in the "main menu" I'm creating, to be some kind of clickable)
As @matiwinnetou also mentioned at IRC: it looks like we're going to have a huge amount of demos, if we keep going like this.
What are we going to do about the huge amount of demos?
README.md
file in the demos/
directory?We can use this issue to keep track of what we want to do about this (upcoming) problem.
The current HUDGround
PriorityLevel
does not have a correct perception of pixels.
If you draw something with width 800
, and have a 1600px
monitor, you will see that the Entity
covers the entire screen, not half.
Even though it's not hard to just do /2 in the users' code, this should be fixed.
Some interfaces require implementation of the Name() string
function, while others require the Type() string
function.
Both are implemented in exactly the same way (which could also be done by reflect
, but that's another story). We should create some consistency and use either one of those.
Thoughts on which one?
I don't know exactly why (yet), but this code runs (after selecting "New Game", and adding 100 entities on-screen), at a mere 17 FPS.
I'm not saying I want to reach 1,8 million fps again (which we'll never reach with rendering), but looking at the things I'm doing, I feel like this should be fixed.
The go profiler says it's mostly external code
๐ .
engi.RenderSystem
.119
in batch.go
):Gl.BufferSubData(Gl.ARRAY_BUFFER, 0, b.vertices)
b.vertices
is of length 200.000
(maximum length) every time. Not sure why that is the case, but it sure is related to the problem.0.1ms
to run, that's too much to handle.Currently when subscribing to an event you pass in the system and the event name. This is clunky and leads to too much message confirmation logic in the default System.Receive(msg Message)
handler.
My proposal is to pass a type func(msg Message)
when subscribing to an event instead.
Any objections?
Docs section at README.md
could use some work.
I'd say we keep those "thoughts" in separate issues, so they can be addressed / discussed in an orderly manner? Some of them are vague (issues would clarify them).
Having spend like hours looking at the code I seem to understand why I cannot render a tile from a tile map or a sprite from a sprite map.
func (r *Region) Render(b *Batch, render *RenderComponent, space *SpaceComponent) {
r.texture.Render(b, render, space)
}
This function simply renders texture, but that is not what I want. When I, however, want to render a sprite it doesn't work with a ECS system. It looks like it's render method has been only implemented for *Batch.
I don't get these batches but even if I did I think this is some legacy from the old forked engine, which does not seem to be ECS based.
Would it make sense to make Sprite "Renderable" so that it satisfies the contract from Renderable type? For me this is the most natural progression but I don't get of this if it has not been implemented due to lack of time or I am missing something fundamental here.
Can you open a Gitter channel please? Have you heard of gitter? It is perfect for OpenSource project, not Slack (IMHO).
When using the example given at the README, I'm getting a FPS of about 30-40k.
It would be nice if we could limit this, since this wastes quite some CPU resources. The programmer could pass/set options somewhere, to set the limit to 30/60/90/120/unlimited whenever he wants. Preferably at runtime (because it'll reside in the game Settings).
Looking at the code here, it's obvious why the FPS is getting this high.
What about something like this?
Wo.New()
ticker := time.NewTicker(time.Duration(int(time.Second) / fpsLimit))
Outer:
for {
select {
case <-ticker.C:
responder.Update(Time.Delta())
window.SwapBuffers()
glfw.PollEvents()
keysUpdate()
Time.Tick()
if window.ShouldClose() {
break Outer
}
}
}
ticker.Stop()
Not sure what the best practice would be if someone were to change the fpsLimit - we'd have to re-create the ticker.
Imagine one having an Entity
, with a RenderComponent
- let's say this is a character in-game.
Now, let's say that this character has a health-bar, a bar that's more/less green, right above his head.
The health-bar is associated with the character, and therefore would be the same Entity
. But as there's only room for one RenderComponent
for that Entity
, it should become another Entity
.
What's the best way to handle this? Two Entity
s that are linked together? (i.e. a ReferenceComponent
, which references to the other Entity
), or is there a way we can say that that Entity
has two RenderComponent
s? What's the best-practice here?
We'd like to support engi
on Android and iOS.
List of thoughts:
Any additional information can be posted in this issue.
(will be added upon when needed)
webgl
a compatibility-layer for https://godoc.org/golang.org/x/mobile/glengo
, w.r.t. the OpenWindow
, RunIteration
, runLoop
functions, a compatibility-layer for https://godoc.org/golang.org/x/mobile/app (Compare https://github.com/EngoEngine/engo/blob/gopherjs/engo_netgo.go with https://github.com/EngoEngine/engo/blob/gopherjs/engo_glfw.go for a general idea on what's needed,As mentioned at their GitHub page, glfw has some dependencies.
For example, on Debian/Ubuntu, you need to:
sudo apt-get install mesa-common-dev xorg-dev libgl1-mesa-dev
These are the only dependencies I've found (so far). I'll leave it up to you if you want to document this, and how you want to document this.
In the ECS paradigm components are designed to only store data, systems are supposed to manipulate this data. The current animation implementation has logic spread between the component and its related system.
Zooming in/out does not reset to 0.
i.e.: zoom in once, and engi
keeps saying you're zooming in.
Some things in engi
don't have idiomatic names.
Examples are:
engi.GetComponent
-> engi.Component
engi.Keys.KEY_SPACE
-> engi.Keys.SPACE
Also: we might want to think about removing engi.Keys.SPACE
(and such) all-together? Since we have engi.Keys.Get(engi.Space)
- which works for every key, and not just a few of them?
warning: code.google.com is shutting down; import path code.google.com/p/freetype-go/freetype will stop working
warning: code.google.com is shutting down; import path code.google.com/p/freetype-go/freetype/raster will stop working
warning: code.google.com is shutting down; import path code.google.com/p/freetype-go/freetype/truetype will stop working
These are referenced at font.go
, and should be replaced with the new import path (github.com/golang/freetype
).
With the term Scene
, I mean something that fills the screen. Such as "level 1 in pacman", or "main menu", or "settings", or "high scores".
How should one handle this / switch between them, in ECS / engi?
My original thought was to add / remove System
s on-the-fly, indicating which would be active and which would not. I am not sure if this is the best/correct way to go, or if there's another (more idiomatic) approach?
@matiwinnetou and I talked about this a few days ago; RemoveEntity
is now implemented at World
, which removes it from the global list of Entity
s, but it also needs to be removed from the specific System
s that update the Entity
.
Imagine we had render.go
where RenderSystem
and RenderComponent
would go, etc
Now it is a bit tricky to navigate around the code, this would make it much easier. Gray areas we could still discuss.
It seems like the examples are broken from when better font support was added.
As Go is such a nice language to do multithreading in, and most games lack multithreading, it'd be nice if we supported it.
Currently, each frame, we are iterating over all System
s, and iterating over all Entity
s "in" those System
s.
I'm not sure if we can safely multithread multiple System
s at once, but we could easily multithread the iteration over Entity
s?
for _, system := range w.Systems() {
if headless && system.SkipOnHeadless() {
continue // so skip it
}
system.Pre()
for _, entity := range system.Entities() {
if w.paused {
ok := entity.GetComponent(&unp)
if !ok {
continue // so skip it
}
}
if entity.Exists {
system.Update(entity, dt)
}
}
system.Post()
}
for _, system := range w.Systems() {
if headless && system.SkipOnHeadless() {
continue // so skip it
}
entities := system.Entities()
system.Pre()
// It's not always faster to multithread; so in this case we're not going to
if len(entities) < 2*runtime.NumCPU() {
for _, ent := range entities {
system.Update(ent, dt)
}
system.Post()
continue // with other Systems
}
entityChannel := make(chan *Entity)
wg := sync.WaitGroup{}
// Launch workers
for i := 0; i < runtime.NumCPU(); i++ {
go func() {
for ent := range entityChannel {
system.Update(ent, dt)
wg.Done()
}
}()
}
// Give them something to do
for _, entity := range entities {
if w.paused {
ok := entity.GetComponent(&unp)
if !ok {
continue // so skip it
}
}
if entity.Exists {
wg.Add(1)
entityChannel <- entity
}
}
// Wait until they're done, before continuing to other Systems
wg.Wait()
close(entityChannel)
system.Post()
}
I know it's a bit more code than the original implementation, but it sure is efficient.
In the README.md
file, it reads:
It's a nice idea, and I would like to use this issue to talk about it - possibly 'accepting' or 'rejecting' it as an idea.
System
- if it's RenderSystem
, we know it. But if it's some kind of MyCustomSystem
, then we wouldn't be able to add it;System
this already?" whenever an Entity
is added.In engi.go
, two variables are globally defined:
var (
responder Responder
Wo Responder
)
They have exactly the same value, and are used for exactly the same. Which one are we keeping?
Side-node, if it's a Responder
(and not a World
), should we even call it Wo
? It took me a while before I noticed why Wo
didn't have the functions / variables available that World
has.
Throughout the codebase there are various pieces of legacy code. These need to be removed.
Sprite
Drawable
(or Renderable
)The current implementation of the PauseSystem
also makes sure that everything that is paused, isn't rendered.
This is because it skips all Entity
s that do not have an UnpauseComponent
- and thus these Entity
s are not passed along to the RenderSystem
. This only showed once #57 was fixed.
The question here is: do we want this behavior? Don't we want this behavior? Do we want to make this behavior optional / default?
I think the tutorial about the Camera would benefit from diagrams / images showing objects in some 2d-plot.
This is quite some effort, so I'd say this is low-priority (you can label it as such).
( Camera Wiki )
Whenever the background music starts, I hear some kind of weird 'popping' sound. Not sure what it is, or how to fix it. Sounds almost like the speakers turning on.
Anyone else hear that sometimes?
With the recent API changes regarding collision messaging, the pong sample found in demos/pong/
is broken.
Would be nice to have a way to "disable" GLFW renderings, and just test the "logic" behind it all. In other words: I want to be able to benchmark engi
, using go test
.
This makes automated tests easier, as well as benchmarking a certain solution (i.e. Message
-usage) - in order to improve its performance.
go test
operationsThe idea is that something has a user-defined default animation (i.e. standing still).
Whenever someone wants to do something (i.e. animate a "grab", "jump", "kick", "nod", etc.), he calls a function and duration:
something.Animate(ACTION_JUMP, time.Second * 0.5)
It animates as it normally would, but instead of repeating it, it would go back to animating the default behavior.
Thoughts? @paked @matiwinnetou
HUDGround
is defined in system.go
, to indicate some kind of HUD. This is good.
This is given a PriorityLevel
, to indicate it must be drawn on top. (i.e. Background
is all at the bottom).
However, the HUD is no affected by the camera (shouldn't move / change size). Since the camera behavior is defined in the Shader (assets.go
, lines 248 and up), we should use other definitions for the HUD.
Related is also batch.go
, line 44.
We should either keep it up-to-date, or remove the link from the README.md
page.
It'd be nice if someone pressed something like ESC
(or something else), it'd pop-up some kind of menu. We all know it; it asks us if we want to continue, change settings, exit, save, load, etc.
But it also stops everything else in the game -- depending on which game you're playing.
width := 600
height := 800
pauseWorld := true
menuEntity := engi.CreateMenu(width, height, pauseWorld)
And this Entity
, would then contain a SpaceComponent
of given size, and one could add some additional components (i.e. RenderComponent
) to do the markup themselves. The pauseWorld
part is why I'd love to see this implemented (by me or someone else).
pauseWorld := true
items := map[string]func() {
"Continue" : func() { /* do nothing */},
"Save" : func() { /* save the game */},
"Exit" : func() { /* exit the game */},
}
menuEntity := engi.CreateMenu(pauseWorld, items)
Then engi
would just create a menu with these options, possibly with some styling options for the user.
Not sure how this fits in the whole ECS-paradigm, but it'd be a nice feature to have. And this issue would be a great place to discuss (or summarize discussions).
The wiki is an excellent place for extra information than the demos offer.
@matiwinnetou offered to do this for the Animation.
( Animation Wiki )
I believe this should be no zoom.
I'm currently working on a game prototype using this engine, but there's a lot of things missing on it for now. So I'm currently committing only to my fork of this project.
Can we have a Trello's to-do list or at least any chat to sync this project's information?
Are you on Gopher's Slack? or IRC?
The GetComponent
function we use, is quite nice. The current usage being:
var comp *SpaceComponent
if !ent.GetComponent(&comp) {
return // not found
}
However, reflect
is quite slow.
An alternative:
var comp *SpaceComponent
interf := ent.GetComponent(comp)
if comp, ok = interf.(*SpaceComponent); !ok {
return // not found
}
But ... This does not feel right, but rewriting it as this isn't perfect either:
var comp *SpaceComponent
var ok bool
comp, ok = ent.GetComponent(comp).(*SpaceComponent)
if !ok {
return // not found
}
Or this:
var comp *SpaceComponent
if comp, ok = ent.GetComponent(comp).(*SpaceComponent); !ok {
return // not found
}
Ignoring the reflect
package and try to manipulate it with the unsafe
package also didn't quite work.
The fastest solution I've come up so far, is this one:
// SPACE_COMPONENT is a uint32 or something, thats generated
// on build-time by the user; the same would be needed for AddComponent, etc.
// or on boot-time, when calling some kind of Register function
comp, ok := ent.GetComponent(SPACE_COMPONENT).(*SpaceComponent)
if !ok {
return // not found
}
I'm not sure what we should do here; if we should do anything at all. All I know for now, is that 20% of the runtime, Go is occupied with the reflect
part of the GetComponent
function (i.e.: that's about 95% of the GetComponent
function duration).
I'm putting it here, because perhaps someone has a nice suggestion as to how to improve this.
The Go Garbage Collector does some strange stuff, as we all know. It even made some benchmarks look quite weird.
I had a point where benchmarking the same function, 5 times, would increase in performance over time (1st benchmark 100%, 5th benchmark 87% of the runtime).
Perhaps we should use runtime.MemStats.EnableGC = false
, to disable GC completely, and then call runtime.GC()
just before we wait for the buffer synchronization (which usually blocks anyway, waiting for the monitor/GPU)?
Thoughts @paked @matiwinnetou ?
We should handle the resizing of the window.
The user should be able to say: I want my things to stretch / shrink as needed (useful for i.e. pong), or to leave the HUD as-is, and just provide a larger/smaller view of "the world" (useful for i.e. Prison Architect, Roller Coaster Tycoon (1+2), etc.)
Currently, the first is implemented. But there's no way to listen for a "ResizeMessage" or something like that.
Right now, when changing the Priority
in a RenderComponent
, it doesn't get rendered correctly.
The current workaround is to add the Entity
to the world again, to ensure the RenderSystem
categorizes things correctly.
Note that this is because of the rendersystem.changed
variable, which makes sure the per-PriorityLevel
list doesn't have to get rebuild on each frame.
Before calling the Setup()
function, we should have set the WorldBounds.Max
value.
Currently, this happens when World
is created, which is after calling Setup()
. If we do so before, users can actually use those default values (or override them if they want to).
Hi,
Nice work, I have been exploring the library and I found that botmark.go
need these changes
type Game struct {
engi.World
}
func (game *Game) Preload() {
engi.Files.Add(engi.NewResource("bot", "data/icon.png"))
}
In order to reduce Garbage Collection, we could keep track of all our Entity
s, and keep them all in the same map
or slice
.
Everything within a []Entity
is ignored for GC, but []*Entity
is being tracked by GC. We could keep one list of all Entity
s.
Not sure if it would increase performance, but it's worth the benchmark.
We currently use:
engi.Color
color.RGBA
uint32
All of these represent colors. We should refactor and use only color.Color
. This allows use of color.RGBA
, and possibly others (it's an interface in the standard library image/color
).
It's open for anyone who wants to do this.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.