aviks / gamezero.jl Goto Github PK
View Code? Open in Web Editor NEWZero overhead game development library for the Julia programming language
License: Other
Zero overhead game development library for the Julia programming language
License: Other
For example, I want this to result in tracing a line along w
's history of positions.
function draw(g::Game)
draw(Circle(w.x, w.y, 1), colorant"gray")
end
For me it just shows the circle moving about as determined by w
's update function, while I'm expecting many little circles showing w
's trajectory.
It seems in certain examples you had to clear the canvas by adding clear()
or fill()
? But for me I see no difference.
https://docs.juliahub.com/GameZero/tTDGf/0.2.1/examples/basic2/
function draw()
fill(current_color)
...
https://docs.juliahub.com/GameZero/tTDGf/0.2.1/examples/Breakout/
function draw()
clear()
...
Is what I'm asking for possible? Sorry if I'm missing something obvious, I'm fairly new to Julia.
Implement a way to print text in the game screen.
Hi all, is there a way to change the polling rate of the mouse/keyboard inputs? I tried looking in event.jl
, but I'm not too familiar with how events are scheduled...
[ Info: Precompiling GameZero [9da27670-f782-11e9-1da1-f53579315bfe] ERROR: LoadError: InitError: could not load library "C:\Users\Administrator\.julia\artifacts\fa03230282478d82c2295049d440075426a17202\bin\SDL2_ima ge.dll"
When running the examples as described in the documentation, "basic.jl" throws the following error:
ERROR: MethodError: Cannot `convert` an object of type
String to an object of type
ARGB
Closest candidates are:
convert(::Type{C}, ::Color, ::Any) where C<:TransparentColor at /home/jts/.julia/packages/ColorTypes/7OlxI/src/conversions.jl:78
convert(::Type{C}, ::C) where C<:Colorant at /home/jts/.julia/packages/ColorTypes/7OlxI/src/conversions.jl:72
convert(::Type{C}, ::Colorant) where C<:Colorant at /home/jts/.julia/packages/ColorTypes/7OlxI/src/conversions.jl:73
...
Stacktrace:
[1] ARGB(x::String)
@ ColorTypes ~/.julia/packages/ColorTypes/7OlxI/src/types.jl:528
[2] GameZero.Screen(name::String, w::Int64, h::Int64, color::String)
@ GameZero ~/.julia/packages/GameZero/e03cc/src/screen.jl:11
[3] initscreen(gm::Module, name::String)
@ GameZero ~/.julia/packages/GameZero/e03cc/src/GameZero.jl:64
[4] initgame(jlf::String, external::Bool)
@ GameZero ~/.julia/packages/GameZero/e03cc/src/GameZero.jl:246
[5] rungame(jlf::String, external::Bool)
@ GameZero ~/.julia/packages/GameZero/e03cc/src/GameZero.jl:195
[6] rungame(jlf::String)
@ GameZero ~/.julia/packages/GameZero/e03cc/src/GameZero.jl:194
[7] top-level scope
@ REPL[2]:1
"basic2.jl" warns about being unable to find ALSA libraries but otherwise simply does not launch a game window:
┌ Warning: No audio device available, sounds and music will not play.
│ ALSA: Couldn't open audio device: Aucun fichier ou dossier de ce type
└ @ GameZero ~/.julia/packages/GameZero/e03cc/src/GameZero.jl:303
versioninfo()
:
Julia Version 1.6.3
Commit ae8452a9e0 (2021-09-23 17:34 UTC)
Platform Info:
OS: Linux (x86_64-unknown-linux-gnu)
CPU: AMD Ryzen 5 5600X 6-Core Processor
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-11.0.0 (ORCJIT, generic)
Environment:
JULIA_LOAD_PATH = :
JULIA_DEPOT_PATH = :/home/jts/.guix-profiles/julia/share/julia/:/home/jts/.guix-profiles/julia/share/julia/
GameZero: 0.2.1
it should display an empty frame if a draw function has not been defined
julia> rungame("MyGame.jl")
ERROR: BoundsError: attempt to access 0-element Array{Method,1} at index [1]
Stacktrace:
[1] getindex at .\array.jl:809 [inlined]
[2] getfn(::Module, ::Symbol, ::Int64) at C:\Users\avik\dev\GameZero\src\GameZero.jl:239
[3] initgame(::String) at C:\Users\avik\dev\GameZero\src\GameZero.jl:219
[4] rungame(::String) at C:\Users\avik\dev\GameZero\src\GameZero.jl:183
[5] top-level scope at REPL[32]:1
We currently suggest users start the Julia repl to run the game. We should provide shell and cmd scripts to run games to make it easier to start from the shell.
At the same time, we should find a better way to start a game programatically, that plays well with modules and include
We store the angle
for an actor, but do not use it transform the image during draw.
First of all, I apologize if this is not an issue.
I noticed that whenever the actor is running, the cpu starts being used and it reaches 25% which causes a drop in the framerates. I am not sure if changing the image of the actor causes this. I tried turning off animations()
to check if the other animations in the environment like the platform and the plants were causing it. It was not that. So my thoughts noticing that pattern was that looping and changing images in a fast way, causes this. I am not sure if this is normal or maybe it is an issue. Thank you.
The images are here.
images.zip
This is how the game looks.
The assets are not mine. Author: https://maaot.itch.io/mossy-cavern
function update(g::Game)
bring_back()
gravity()
animations()
#####################
#WALKING AND RUNNING#
#####################
global STEP, IDLE, VELOCITY, LOOKING_AT
if g.keyboard.LCTRL && g.keyboard.D #RUNNING TO THE RIGHT SIDE
LOOKING_AT = 0
VELOCITY = 0
if VELOCITY < 50
VELOCITY += 1
end
STEP += 1
witch.image = "wr$(STEP).png"
witch.x += 3
witch.image = "wr$(STEP).png"
if STEP == 18
STEP = 1
end
elseif g.keyboard.LCTRL && g.keyboard.A #RUNNING TO THE LEFT SIDE
LOOKING_AT = 1
VELOCITY = 0
if VELOCITY < 5
VELOCITY += 1
end
STEP += 1
witch.image = "wr$(STEP).png"
witch.x -= 3
witch.image = "wl$(STEP).png"
if STEP == 18
STEP = 1
end
elseif g.keyboard.A
LOOKING_AT = 1
VELOCITY += 2
STEP += 1
witch.image = "wl$(STEP).png"
witch.x -= 2
if STEP == 18
STEP = 1
end
elseif g.keyboard.D
LOOKING_AT = 0
VELOCITY += 2
STEP += 1
witch.image = "wr$(STEP).png"
witch.x += 2
if STEP == 18
STEP = 1
end
else
################
#IDLE ANIMATION#
################
LOOKING_AT = 2 #LOOKING AT CENTER
IDLE += 0.35
witch.image = "i$(round(Int, IDLE)).png"
if round(Int, IDLE) == 18
IDLE = 1
end
VELOCITY = 0
end
end
While trying out Flappy Bird and tinkering with it, I stumbled accross some strange things.
we have actor.right < actor.left
:
(pipe_top.right, pipe_top.left) = (228, 328)
(pipe_top.right, pipe_top.left) = (225, 325)
(pipe_top.right, pipe_top.left) = (222, 322)
it seems like right
is computed as left - width
. shouldn't it be left + width
or am I missing something ?
Lines 87 to 90 in 938cc41
EDIT: same thing for bottom
So I was trying to organize a game and I wanted to split it up in multiple files but then I realized after many errors that GameZero can't do multiple files (I think it can't I am not entirely sure but if it is true it can't do multiple files please consider making it able to because it would make productivity a lot better and less messy).
I'm curious if theres any plan to put in gamepad support, given its SDL2 it should be doable I assume?
Right now, all Game objects are concrete. However, it may be worthwhile to abstract out things right now.
Primarily, Game
and Actor
must be subtypes of AbstractGame
and AbstractActor
, which themselves can be concretised to Actor
and Game
. Functions which can be abstracted should be.
Hi, following up the discussion on JuliaCon discord, here is the report of the bug I found on my system. The game only uses a quarter of the window. I think it actually displays a window which is twice wide and twice taller than defined.
I attach screenshots of two of the games form SquidSinker/GZExamples. They define HEIGHT = 600
and WIDTH = 600
, but the windows have twice the height and twice the width, as seen from the pixel count on the screenshots.
Here is the info of my set up:
(gamezero) pkg> st
Status `~/Documents/git_repositories/julia/julia_random_stuff/gamezero/Project.toml`
[5ae59095] Colors v0.12.8
[9da27670] GameZero v0.2.1
julia> versioninfo()
Julia Version 1.6.2
Commit 1b93d53fc4 (2021-07-14 15:36 UTC)
Platform Info:
OS: macOS (x86_64-apple-darwin18.7.0)
CPU: Intel(R) Core(TM) m5-6Y54 CPU @ 1.10GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-11.0.1 (ORCJIT, skylake)
Environment:
JULIA_NUM_THREADS = 2
P.S.: The sound issue that I also mentioned didn't happen again. Sound is coming out fine. I might have done something wrong. Great, one less problem!
I tried to run the file in the example directory and got an error. I see the same error when I tried GZExamples. Any idea? I installed master of SimpleMediaLayer and GameZero. I'm on M1 Mac and sdl2 libraries are installed by homebrew.
julia> using GameZero
julia> rungame("~/.julia/packages/GameZero/e03cc/example/BasicGame/basic.jl")
ERROR: UndefVarError: libsdl2_ttf not defined
Stacktrace:
[1] TTF_Init
@ ~/.julia/packages/SimpleDirectMediaLayer/gJANO/src/LibSDL2.jl:5233 [inlined]
[2] initSDL()
@ GameZero ~/.julia/packages/GameZero/17XG0/src/GameZero.jl:284
[3] initgame(jlf::String, external::Bool)
@ GameZero ~/.julia/packages/GameZero/17XG0/src/GameZero.jl:208
[4] rungame(jlf::String, external::Bool)
@ GameZero ~/.julia/packages/GameZero/17XG0/src/GameZero.jl:186
[5] rungame(jlf::String)
@ GameZero ~/.julia/packages/GameZero/17XG0/src/GameZero.jl:185
[6] top-level scope
@ REPL[5]:1
julia> versioninfo()
Julia Version 1.7.2
Commit bf53498635 (2022-02-06 15:21 UTC)
Platform Info:
OS: macOS (arm64-apple-darwin21.2.0)
CPU: Apple M1 Max
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-12.0.1 (ORCJIT, cyclone)
Environment:
JULIA_GR_PROVIDER = GR
(@v1.7) pkg> st GameZero SimpleDirectMediaLayer
Status `~/.julia/environments/v1.7/Project.toml`
[9da27670] GameZero v0.3.0 `https://github.com/aviks/GameZero.jl.git#master`
[98e33af6] SimpleDirectMediaLayer v0.3.0 `https://github.com/JuliaMultimedia/SimpleDirectMediaLayer.jl.git#master`
$ brew list|grep sdl2
sdl2
sdl2_gfx
sdl2_image
sdl2_mixer
sdl2_net
sdl2_ttf
I'm having some problems with the actors that I load into a game.
After some time (I haven't yet been able to determine a rhyme or reason yet, but usually after there are a few sprites in play or after 10~15 seconds) the actors all disappear and I'm left with an empty screen. I can still hear music and sounds being activated, just no visuals. Closing the game and reloading usually works (sometime it just hangs, forcing a Julia reboot) and it will draw the actors again until they disappear again.
Has anyone else had a similar issue?
Hi, I'm getting this error:
julia> go()
ALSA lib conf.c:4133:(snd_config_update_r) Cannot access file /workspace/destdir/share/alsa/alsa.conf
ALSA lib conf.c:4133:(snd_config_update_r) Cannot access file /workspace/destdir/share/alsa/alsa.conf
ALSA lib pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM default
┌ Warning: No audio device available, sounds and music will not play.
│ ALSA: Couldn't open audio device: No such file or directory
└ @ GameZero ~/.julia/packages/GameZero/JN07Y/src/GameZero.jl:292
ALSA lib conf.c:4133:(snd_config_update_r) Cannot access file /workspace/destdir/share/alsa/alsa.conf
ALSA lib conf.c:4133:(snd_config_update_r) Cannot access file /workspace/destdir/share/alsa/alsa.conf
I don't understand how GZ connects to ALSA, but of course there's no /workspace
directory on my system. Sound works fine outside of this. Here's my sound setup:
➤ inxi -xxA
Audio: Device-1: Advanced Micro Devices [AMD] Family 17h HD Audio vendor: Gigabyte driver: snd_hda_intel v: kernel
bus-ID: 0a:00.3 chip-ID: 1022:1457
Device-2: NVIDIA TU102 High Definition Audio vendor: ASUSTeK driver: snd_hda_intel v: kernel bus-ID: 41:00.1
chip-ID: 10de:10f7
Device-3: Logitech C922 Pro Stream Webcam type: USB driver: snd-usb-audio,uvcvideo bus-ID: 1-1:2 chip-ID: 046d:085c
Device-4: Logitech Blue Microphones type: USB driver: hid-generic,snd-usb-audio,usbhid bus-ID: 1-3:3
chip-ID: 046d:0ab7
Device-5: Valve Valve VR Radio type: USB driver: cdc_acm,hid-generic,usbhid bus-ID: 3-1.3.2:8 chip-ID: 28de:2102
Device-6: Valve Valve VR Radio & HMD Mic type: USB driver: hid-generic,snd-usb-audio,usbhid bus-ID: 3-1.3.3:9
chip-ID: 28de:2102
Sound Server-1: ALSA v: k5.10.49-1-MANJARO running: yes
Sound Server-2: sndio v: N/A running: no
Sound Server-3: JACK v: 1.9.18 running: no
Sound Server-4: PulseAudio v: 14.2 running: no
Sound Server-5: PipeWire v: 0.3.31 running: yes
Is GameZero going to get updated. Else, are there some alternatives, for interactive Reinforcement Learning environments?
Thanks
is it possible to control render?
like user decide when to draw objects and when not to draw objects(for faster execution sometimes we don't need rendering, like while training a deep learning agent)
Hello and thanks for creating this package!
I would like to create Actor
s from raw pixel data which I dynamically generate, instead of passing an image file that is stored on disk.
What I've tried so far:
using GameZero
using PNGFiles
using SimpleDirectMediaLayer
using SimpleDirectMediaLayer.LibSDL2
function MyActor(image; kv...)
height, width = size(image)
raw_pixeldata = UInt8[]
for pixel in 255 * vec(image')
push!(raw_pixeldata, red(pixel))
push!(raw_pixeldata, green(pixel))
push!(raw_pixeldata, blue(pixel))
push!(raw_pixeldata, alpha(pixel))
end
# sf = SimpleDirectMediaLayer.LibSDL2.SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0)
# sf.pixels = Ref{Vector{UInt8}}(raw_pixeldata) # doesn't work: type Ptr has no field pixels
sf = SimpleDirectMediaLayer.LibSDL2.SDL_CreateRGBSurfaceWithFormatFrom(raw_pixeldata, width, height, 8, 4, SimpleDirectMediaLayer.LibSDL2.SDL_PIXELFORMAT_RGBA8888)
w, h = size(sf)
a = GameZero.Actor("", sf, Rect(0, 0, Int(w), Int(h)), [1.0, 1.0], 0, 255, Dict{Symbol,Any}())
for (k, v) in kv
setproperty!(a, k, v)
end
return a
end
image = PNGFiles.load("image.png") # this is just a simple example, in practice I want to generate it dynamically in the code
actor = MyActor(image) # doesn't work
I tried to use functions like SDL_CreateRGBSurface or SDL_CreateRGBSurfaceWithFormatFrom, but unfortunately I can't get it to work. The problem is that I don't know how to pass the pixel data to these functions. The SDL C API seems to expect a pointer void *pixels
, but I'm not very familiar with C and I have no clue how to do that in Julia. I've also tried various combinations like Ref{Vector{UInt8}}(raw_pixeldata)
, Ref{Cvoid}(raw_pixeldata)
, etc., but nothing of it worked (and basically I don't really know what I'm doing here).
The Julia wrapper for the SDL function looks like
function SDL_CreateRGBSurfaceWithFormatFrom(pixels, width, height, depth, pitch, format)
ccall((:SDL_CreateRGBSurfaceWithFormatFrom, libsdl2), Ptr{SDL_Surface}, (Ptr{Cvoid}, Cint, Cint, Cint, Cint, Uint32), pixels, width, height, depth, pitch, format)
end
but this doesn't help me much either.
https://github.com/JuliaMultimedia/SimpleDirectMediaLayer.jl/blob/82c79b94289b65d2ad15f89363a632041c0d7c06/src/LibSDL2.jl#L1773-L1787
The code above crashes with a long error message
Please submit a bug report with steps to reproduce this fault, and any error messages that follow (in their entirety). Thanks.
Exception: EXCEPTION_ACCESS_VIOLATION at 0x1feebdc5840 -- unsafe_load at .\pointer.jl:119 [inlined]
unsafe_load at .\pointer.jl:119 [inlined]
...
Does anybody know how to use one of the linked SDL functions and could help me; or would you consider to create a constructor for Actor
which allows to pass the image data directly (e.g. a Matrix{RGBA}
from the Images.jl/ImageIO.jl packages)?
In order to have the same style as Julia, methods like getPos
should be changed (if needed) to something like getpos
.
Base.IOError("readdir(\"./images\"): too many open files (EMFILE)", -24)
I made my own version of the flappy bird game, and I face this issue if I play it for a while. It looks like GameZero is not GC-ing some images(?)
Note, I change the bird image everytime I press space, and for a game like flappy bird, that is quite often. I thought the image will be reused?
We currently only support background colors, not images.
There appears to be some form of timing issue when using GameZero in Linux.
As an example, it takes less than 1/2 a second for the bird in flappy bird to hit the pipe, an reset the game continuously.
I get the same blazing fast performance with the basic.jl
example.
Games crash when pressing a key that is not in Keys.Key
, for example non-english characters (here ù
) or special keys (like volume up)
julia> rungame("GZExamples\\Spaceship\\Spaceship.jl")
┌ Warning: Use lowercases names for resource files. It is safer when moving between windows and unix: Space_pod.png
└ @ GameZero C:\Users\user\.julia\packages\GameZero\QdBGK\src\resources.jl:103
┌ Error: ArgumentError("invalid value for Enum Key: 249")
│ exception =
│ ArgumentError: invalid value for Enum Key: 249
│ Stacktrace:
│ [1] enum_argument_error(typename::Symbol, x::UInt32)
│ @ Base.Enums .\Enums.jl:79
│ [2] Key
│ @ .\Enums.jl:192 [inlined]
│ [3] handleKeyPress(g::Game, e::Vector{UInt8}, t::UInt32)
│ @ GameZero ~\.julia\packages\GameZero\QdBGK\src\GameZero.jl:143
│ [4] handleEvents!
│ @ ~\.julia\packages\GameZero\QdBGK\src\GameZero.jl:126 [inlined]
│ [5] mainloop(g::Game)
│ @ GameZero ~\.julia\packages\GameZero\QdBGK\src\GameZero.jl:95
│ [6] rungame(jlf::String)
│ @ GameZero ~\.julia\packages\GameZero\QdBGK\src\GameZero.jl:186
│ [7] top-level scope
│ @ REPL[25]:1
│ [8] eval(m::Module, e::Any)
│ @ Core .\boot.jl:360
│ [9] eval_user_input(ast::Any, backend::REPL.REPLBackend)
│ @ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:139
│ [10] repl_backend_loop(backend::REPL.REPLBackend)
│ @ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:200
│ [11] start_repl_backend(backend::REPL.REPLBackend, consumer::Any)
│ @ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:185
│ [12] run_repl(repl::REPL.AbstractREPL, consumer::Any; backend_on_current_task::Bool)
│ @ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:317
│ [13] run_repl(repl::REPL.AbstractREPL, consumer::Any)
│ @ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:305
│ [14] (::Base.var"#878#880"{Bool, Bool, Bool})(REPL::Module)
│ @ Base .\client.jl:387
│ [15] #invokelatest#2
│ @ .\essentials.jl:707 [inlined]
│ [16] invokelatest
│ @ .\essentials.jl:706 [inlined]
│ [17] run_main_repl(interactive::Bool, quiet::Bool, banner::Bool, history_file::Bool, color_set::Bool)
│ @ Base .\client.jl:372
│ [18] exec_options(opts::Base.JLOptions)
│ @ Base .\client.jl:302
│ [19] _start()
│ @ Base .\client.jl:485
└ @ GameZero C:\Users\user\.julia\packages\GameZero\QdBGK\src\GameZero.jl:189
if gameover == false
display = "分數(Score) = $score"
else
display = "GAME OVER! Final Score = $score"
#play again instructions
replay = TextActor("Click to play Again, 點擊...再玩", sDspFont; font_size = 26, color = Int[0, 0, 0, 255])
replay.pos = (135, 390)
draw(replay)
end
julia> rungame("basic.jl")
libGL error: MESA-LOADER: failed to open iris: /home/miguel/bin/julia-1.6.2/bin/../lib/julia/libstdc++.so.6: version `GLIBCXX_3.4.29' not found (required by /usr/lib/dri/iris_dri.so) (search paths /usr/lib/dri)
libGL error: failed to load driver: iris
libGL error: MESA-LOADER: failed to open iris: /home/miguel/bin/julia-1.6.2/bin/../lib/julia/libstdc++.so.6: version `GLIBCXX_3.4.29' not found (required by /usr/lib/dri/iris_dri.so) (search paths /usr/lib/dri)
libGL error: failed to load driver: iris
libGL error: MESA-LOADER: failed to open swrast: /home/miguel/bin/julia-1.6.2/bin/../lib/julia/libstdc++.so.6: version `GLIBCXX_3.4.29' not found (required by /usr/lib/dri/swrast_dri.so) (search paths /usr/lib/dri)
libGL error: failed to load driver: swrast
X Error: BadValue
Request Major code 152 (GLX)
Request Minor code 3 ()
Value 0x0
Error Serial #103
Current Serial #104
~ $
This looks to me like an incompatibility between Julia's bundled libstdc++ and my system drivers. Is there a way to make GameZero use my system's libstdc++?
I would like to draw some basic forms with soma angle.
I looked aroud the code and didn't find anything to do that.
Is there some native way of doing it?
If there is not, I could implement my own simple Rect object made with four Lines, but I dont know how to fill this 4 lines in the Draw function
There is a description only in the other package of game examples, but it should be here as well:
pkg> add https://github.com/aviks/GameZero.jl
julia> using GameZero
julia> GameZero.rungame("C:\path\to\GZExamples\Spaceship\Spaceship.jl")
I tested basic.jl and found that the graphics are only shown in the top-left quadrant of the window on my Mac. I guess high DPI (retina) screen is not supported. The background image is shown correctly maybe because it is a texture that fills the whole surface.
I see some code which may be related to high DPI screen in window.jl but I have no idea how to fix it...
The same issue exists in all the other examples (basic2.jl and ones in GZExamples).
I suggest that work should be started on making a built in physics system.
There are several bindings for things like chipmunk that could be used, but I propose that we could build one for GameZero. I have found the beginnings of a Julia Physics System called Matter.jl that could be used to do this.
The links in the ReadMe are dead.
It would be nice to have traingles, or perhaps more generally polygons.
Based on the docs, I got the impression that Circle
should have the same properties as Actor
. So I ran into an problem where my code runs on actors using a.pos
, but then it didn't work with Circle
s e.g. c.pos
was "nothing".
Circle
has the same API/properties asActor
.
Game objects on-screen are represented as Actors which have several associated attributes. Using Actors, you can change position, change the image and check for collisions. However, not all moving parts need to be Actors as those without a specific image can be defined as a Circle or a Rect, which have the same associated attributes (apart from image). Actors are usually the primary game objects that you move around.GameZero.jl also includes basic geometric shapes. Rects, Circles and Lines can be used to do everything an Actor can, having the same attributes (apart from image).
This might also apply to Rect
, Triangle
, and Line
as well.
Possible solutions:
Actor
, Circle
, etc., allowing one to set and get position, and other properties.a=Actor("/home/jmarcellopereira/images/bloco.png");
ERROR: UndefRefError: access to undefined reference
Stacktrace:
[1] getproperty at ./Base.jl:33 [inlined]
[2] getindex at ./refvalue.jl:32 [inlined]
[3] file_path(::String, ::Symbol) at /home/jmarcellopereira/.julia/packages/GameZero/QdBGK/src/resources.jl:45
[4] image_surface(::String) at /home/jmarcellopereira/.julia/packages/GameZero/QdBGK/src/resources.jl:36
[5] Actor(::String; kv::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at /home/jmarcellopereira/.julia/packages/GameZero/QdBGK/src/actor.jl:18
[6] Actor(::String) at /home/jmarcellopereira/.julia/packages/GameZero/QdBGK/src/actor.jl:18
[7] top-level scope at REPL[2]:1
i tried the code twice and it was throwing an error in both
also some times it stuck(when i'm not drawing objects, it stuck for long time), it's much slower than pygame as i expected it to be much more faster(or i've made a mistake in my code)
it may take few hours to get the error, usually between 3000-4000 episodes
using Flux
using Zygote
using Flux: gradient, params, ADAM, Momentum
using Flux.Losses: huber_loss
using Gym
using Distributions: Categorical, logpdf
using Statistics: mean, std
# ------------------------ MEMORY ---------------------------
mutable struct Memory
states::Vector{Vector{Float32}}
actions::Vector{Int}
rewards::Vector{Float32}
dones::Vector{Bool}
log_probs::Vector{Float32}
end
function vector2matrix(input_vec::Vector{Vector{Float32}})
nrows = length(input_vec)
ncols = length(input_vec[1])
matrix = zeros(Float32, ncols, nrows)
for i ∈ 1:nrows
matrix[:, i] = input_vec[i]
end
matrix
end
function matrix2vector(input_matrix)
vector = Array{Vector{Float32}, 1}()
for i ∈ 1:size(input_matrix, 2)
push!(vector, input_matrix[:, i])
end
vector
end
function clear_memory(m::Memory)
m.states = []
m.actions = []
m.rewards = []
m.dones = []
m.log_probs = []
end
# ------------------------- model --------------------------------
function build_networks(input_dim, output_dim, hidden_dim)
actor = Chain(
Dense(input_dim, hidden_dim, tanh),
Dense(hidden_dim, hidden_dim, tanh),
Dense(hidden_dim, output_dim),
softmax
)
critic = Chain(
Dense(input_dim, hidden_dim, tanh),
Dense(hidden_dim, hidden_dim, tanh),
Dense(hidden_dim, 1)
)
actor, critic
end
mutable struct Model
actor::Chain
critic::Chain
end
Flux.@functor Model
# --------------------------- agent -----------------------------
mutable struct PPO
old_policy::Model
policy::Model
gamma::Float32
update_every::Int
update_step::Int
opt
memory::Memory
eps_clip::Float32
k_epochs::Int
state_values::Vector{Float32}
log_probs::Vector{Float32}
end
function PPO(state_dim::Int, action_dim::Int, hidden_dim::Int, lr, gamma, k_epochs, eps_clip, update_every, memory)
println(state_dim, action_dim, hidden_dim)
actor, critic = build_networks(state_dim, action_dim, hidden_dim)
old_policy = Model(actor, critic)
policy = Model(actor, critic)
opt = ADAM(lr)
update_step = 0
state_values = [0.0]
log_probs = [0.0]
PPO(
old_policy,
policy,
gamma,
update_every,
update_step,
opt,
memory,
eps_clip,
k_epochs,
state_values,
log_probs
)
end
function select_action(agent::PPO, state::Vector{Float32}, train_mode::Bool)
probs = agent.old_policy.actor(state)
dist = Categorical(probs)
action = rand(dist)
if train_mode
log_prob = logpdf(dist, action)
push!(agent.memory.states, state)
push!(agent.memory.actions, action)
push!(agent.memory.log_probs, log_prob)
end
action
end
function take_step(agent::PPO, reward, done)
push!(agent.memory.rewards, reward)
push!(agent.memory.dones, done)
agent.update_step += 1
if agent.update_step % agent.update_every == 0
train(agent)
clear_memory(agent.memory)
end
end
function update_target!(target, model; τ = 1f0)
for (p_t, p_m) in zip(params(target), params(model))
p_t .= (1f0 - τ) * p_t .+ τ * p_m
end
end
function train(agent::PPO)
states = vector2matrix(agent.memory.states)
rewards = Array{Float32, 1}()
discounted_reward = 0.0
for (reward, done) ∈ zip(reverse(agent.memory.rewards), reverse(agent.memory.dones))
if done
discounted_reward = 0.0
end
discounted_reward = reward + agent.gamma * discounted_reward
insert!(rewards, 1, discounted_reward)
end
rewards = (rewards .- mean(rewards)) ./ (std(rewards) .+ 1e-5)
for _ ∈ 1:agent.k_epochs
gs = gradient(params(agent.policy.critic)) do
state_values = vec(agent.policy.critic(states))
Zygote.ignore() do
agent.state_values = state_values
end
huber_loss(state_values, rewards)
end
Flux.Optimise.update!(agent.opt, params(agent.policy.critic), gs)
gs = gradient(params(agent.policy.actor)) do
advantages = rewards .- agent.state_values
probs = agent.policy.actor(states)
probs_lst = [probs[:, i] for i ∈ 1:size(probs, 2)]
dist = [Categorical(x) for x ∈ probs_lst]
entropies = map(x -> -sum(x .- log.(x)), probs_lst)
log_probs = logpdf.(dist, agent.memory.actions)
ratio = exp.(log_probs .- agent.memory.log_probs)
surr1 = ratio .* advantages
surr2 = clamp.(ratio, 1 - agent.eps_clip, 1 + agent.eps_clip) .* advantages
loss = mean(-min.(surr1, surr2))
loss
end
Flux.Optimise.update!(agent.opt, params(agent.policy.actor), gs)
end
update_target!(agent.old_policy.critic, agent.policy.critic)
update_target!(agent.old_policy.actor, agent.policy.actor)
end
# ----------------------------------- train -----------------------------------
function train_loop()
env = GymEnv("CartPole-v1")
state_dim = env.observation_space.shape[1]
action_dim = env.action_space.n
memory = Memory([], [], [], [], [])
agent = PPO(state_dim, action_dim, 128, 0.001, 0.99, 4, 0.2, 2000, memory)
total_reward = 0
for episode ∈ 1:100000
state = reset!(env)
for _ ∈ 1:2000
action = select_action(agent, state)
state, reward, done, _ = step!(env, action - 1)
total_reward += reward
take_step(agent, reward, done)
if done
break
end
end
if episode % 20 == 0
avg_reward = total_reward / 20
total_reward = 0
@info "Episode : $episode | avg_reward : $avg_reward"
end
end
end
# -------------------------------------------- GAME ------------------------------------------------------------------------
using GameZero
using Colors
WIDTH = 400
HEIGHT = 400
WHITE = colorant"white"
BLUE = colorant"blue"
RED = colorant"red"
YELLOW = colorant"yellow"
BACKGROUND = WHITE
initial_x = 200
initial_y = 200
BLOCKSIZE = 20
mutable struct SnakeEnv
SCORE::Int
DIRECTION::String
done::Bool
state::Vector{Float32}
reward::Float32
allow_render::Bool
snake::Vector{Rect}
food::Rect
step::Int
use_first_state::Bool
txt
end
directions_lst = ["right", "left", "up", "down"]
function place_food(snake)
food_x = rand(1:WIDTH - BLOCKSIZE)
food_y = rand(1:HEIGHT - BLOCKSIZE)
food_obj = Rect(food_x, food_y, BLOCKSIZE, BLOCKSIZE)
if any(map(x -> collide(x, food_obj), snake))
place_food(snake)
end
food_obj
end
function get_state_1(env::SnakeEnv)
danger_right_1, danger_left_1, danger_up_1, danger_down_1 = check_danger(env, 1)
danger_right_2, danger_left_2, danger_up_2, danger_down_2 = check_danger(env, 2)
danger_right_3, danger_left_3, danger_up_3, danger_down_3 = check_danger(env, 3)
danger_right_4, danger_left_4, danger_up_4, danger_down_4 = check_danger(env, 4)
state = [danger_right_1, danger_left_1, danger_up_1, danger_down_1,
danger_right_2, danger_left_2, danger_up_2, danger_down_2,
danger_right_3, danger_left_3, danger_up_3, danger_down_3,
danger_right_4, danger_left_4, danger_up_4, danger_down_4]
head = env.snake[1]
tail = env.snake[end]
food = env.food
head.x > food.x ? push!(state, 1) : push!(state, 0)
head.y > food.y ? push!(state, 1) : push!(state, 0)
tail.x > food.x ? push!(state, 1) : push!(state, 0)
tail.y > food.y ? push!(state, 1) : push!(state, 0)
head.x > tail.x ? push!(state, 1) : push!(state, 0)
head.y > tail.y ? push!(state, 1) : push!(state, 0)
# add directions
for dir ∈ directions_lst
dir == env.DIRECTION ? push!(state, 1.0) : push!(state, 0.0)
end
env.state = state
end
function get_state_2(env::SnakeEnv)
danger_right_1, danger_left_1, danger_up_1, danger_down_1 = check_danger(env, 1)
head = env.snake[1]
mid = env.snake[Int(round(length(env.snake) / 2))]
tail = env.snake[end]
food = env.food
dir = findfirst(x -> x == env.DIRECTION, directions_lst)[1]
state = [ mid.x / WIDTH, mid.y / HEIGHT, length(env.snake) / WIDTH,
head.x / WIDTH, head.y / HEIGHT, tail.x / WIDTH, tail.y / HEIGHT,
(head.x - food.x) / WIDTH, (head.y - food.y) / HEIGHT, (tail.x - food.x) / WIDTH, (tail.y - food.y) / HEIGHT,
food.x / WIDTH, food.y / HEIGHT,
dir / 4]
env.state = state
end
function reset(env::SnakeEnv)
env.snake = [Rect(initial_x, initial_y, BLOCKSIZE, BLOCKSIZE),
Rect(initial_x - BLOCKSIZE, initial_y, BLOCKSIZE, BLOCKSIZE),
Rect(initial_x - 2 * BLOCKSIZE, initial_y, BLOCKSIZE, BLOCKSIZE)]
env.food = place_food(env.snake)
env.done = false
env.reward = 0
env.step = 1
env.SCORE = 0
env.DIRECTION = "right"
env.txt = TextActor("Score : $(env.SCORE)", "moonhouse")
if env.use_first_state
get_state_1(env)
else
get_state_2(env)
end
end
function draw_objects(env::SnakeEnv)
head = env.snake[1]
body = env.snake[2:end]
draw(head, YELLOW, fill=true)
map(x -> draw(x, BLUE), body)
draw(env.food, RED, fill=true)
draw(env.txt)
end
function game_over(env::SnakeEnv)
head = env.snake[1]
if head.x > WIDTH - BLOCKSIZE || head.x < 0 || head.y > HEIGHT - BLOCKSIZE || head.y < 0
return true, -10
end
if env.step > 30 * length(env.snake)
return true, -10
end
if any(map(x -> collide(x, head), env.snake[3:end]))
return true, -100
end
return false, 0
end
function check_danger(env::SnakeEnv, step_size::Int)
head = env.snake[1]
danger_right = env.DIRECTION == "right" && (head.x + step_size * BLOCKSIZE > WIDTH - BLOCKSIZE) ? 1.0 : 0.0
danger_left = env.DIRECTION == "left" && (head.x - step_size * BLOCKSIZE) < 0 ? 1.0 : 0.0
danger_up = env.DIRECTION == "up" && (head.y - step_size * BLOCKSIZE) < 0 ? 1.0 : 0.0
danger_up_down = env.DIRECTION == "down" && (head.y + step_size * BLOCKSIZE) > HEIGHT - BLOCKSIZE ? 1.0 : 0.0
danger_right, danger_left, danger_up, danger_up_down
end
function move_snake(env::SnakeEnv)
h_x = env.snake[1].x
h_y = env.snake[1].y
if env.DIRECTION == "right"
insert!(env.snake, 1, Rect(h_x + BLOCKSIZE, h_y, BLOCKSIZE, BLOCKSIZE))
elseif env.DIRECTION == "left"
insert!(env.snake, 1, Rect(h_x - BLOCKSIZE, h_y, BLOCKSIZE, BLOCKSIZE))
elseif env.DIRECTION == "up"
insert!(env.snake, 1, Rect(h_x, h_y - BLOCKSIZE, BLOCKSIZE, BLOCKSIZE))
else
insert!(env.snake, 1, Rect(h_x, h_y + BLOCKSIZE, BLOCKSIZE, BLOCKSIZE))
end
end
function step(env::SnakeEnv, action::Int)
env.step += 1
if action == 1 && env.DIRECTION != "up"
env.DIRECTION = "down"
elseif action == 2 && env.DIRECTION != "down"
env.DIRECTION = "up"
elseif action == 3 && env.DIRECTION != "left"
env.DIRECTION = "right"
elseif action == 4 && env.DIRECTION != "right"
env.DIRECTION = "left"
end
# update snake position
move_snake(env)
# check game over
env.done, env.reward = game_over(env)
if env.done
if env.use_first_state
get_state_1(env)
else
get_state_2(env)
end
return env.state, env.reward, env.done, env.SCORE
end
if collide(env.snake[1], env.food)
env.SCORE += 1
env.food = place_food(env.snake)
env.reward = 10
else
pop!(env.snake)
end
env.txt = TextActor("Score : $(env.SCORE)", "moonhouse")
if env.use_first_state
get_state_1(env)
else
get_state_2(env)
end
return env.state, env.reward, env.done, env.SCORE
end
# -------------------- CREATE ENV ---------------------------------
snake_env = [Rect(initial_x, initial_y, BLOCKSIZE, BLOCKSIZE),
Rect(initial_x - BLOCKSIZE, initial_y, BLOCKSIZE, BLOCKSIZE),
Rect(initial_x - 2 * BLOCKSIZE, initial_y, BLOCKSIZE, BLOCKSIZE)]
food_env = place_food(snake_env)
env = SnakeEnv(0, "right", false, [0.0], 0.0, true, snake_env, food_env, 1, true, TextActor("Score : 0", "moonhouse"))
reset(env)
state_dim = length(env.state)
action_dim = 4
memory = Memory([], [], [], [], [])
agent = PPO(state_dim, action_dim, 128, 0.001, 0.99, 4, 0.2, 2000, memory)
function draw(g::Game)
if env.allow_render
sleep(0.03)
draw_objects(env)
end
end
# ---------------------------- loop ------------------------------
episode = 0
total_reward = 0
record = 0
function print_info(episode, total_reward, record)
env.allow_render = true
avg_reward = total_reward / 20
println("Episode : $episode | avg_reward : $avg_reward | record : $record")
end
function onetime_loop()
action = select_action(agent, env.state, false)
next_state, reward, done, SCORE = step(env, action)
if done
env.allow_render = false
reset(env)
end
end
function full_loop()
global episode, total_reward, record
while !env.done
action = select_action(agent, env.state, true)
next_state, reward, done, SCORE = step(env, action)
take_step(agent, reward, done)
total_reward += reward
end
episode += 1
if episode % 20 == 0
print_info(episode, total_reward, record)
total_reward = 0
else
env.allow_render = false
end
if env.SCORE > record
record = env.SCORE
end
reset(env)
end
function update(g::Game)
env.allow_render ? onetime_loop() : full_loop()
end
Please submit a bug report with steps to reproduce this fault, and any error messages that follow (in their entirety). Thanks.
Exception: EXCEPTION_ACCESS_VIOLATION at 0x6d642194 -- TTF_SizeUTF8_Internal at /workspace/srcdir/SDL2_ttf-2.0.15\SDL_ttf.c:1185
in expression starting at REPL[2]:1
TTF_SizeUTF8_Internal at /workspace/srcdir/SDL2_ttf-2.0.15\SDL_ttf.c:1185
TTF_RenderUTF8_Blended at /workspace/srcdir/SDL2_ttf-2.0.15\SDL_ttf.c:1630
TTF_RenderText_Blended at /workspace/srcdir/SDL2_ttf-2.0.15\SDL_ttf.c:1600
TTF_RenderText_Blended at C:\Users\Administrator.julia\packages\SimpleDirectMediaLayer\wjMsP\src\LibSDL2.jl:6038 [inlined]
#TextActor#12 at C:\Users\Administrator.julia\packages\GameZero\q74y7\src\actor.jl:35
TextActor at C:\Users\Administrator.julia\packages\GameZero\q74y7\src\actor.jl:33 [inlined]
step at C:\Users\Administrator\Desktop\julia\snake.jl:445
full_loop at C:\Users\Administrator\Desktop\julia\snake.jl:515
update at C:\Users\Administrator\Desktop\julia\snake.jl:537
unknown function (ip: 0000022c242fc776)
Please submit a bug report with steps to reproduce this fault, and any error messages that follow (in their entirety). Thanks.
Exception: UNKNOWN at 0x7ffdd3cc49b9 --
It would be great to have 1 file that contains the game and include other files that contains the structs created in the game.
I was tring to make a game.jl that had "include(snake.jl)".
In game.jl, all the loops and conditions would be verified, while the snake.jl file would have the definition of the struct snake and its methods. But when i try to do "include(snake.jl)" I get "LoadError: UndefVarError: include not defined".
Apperantly, there's no function "include" in gamezero, or it erases the base function from julia. I don't uderstand exactly
This issue is used to trigger TagBot; feel free to unsubscribe.
If you haven't already, you should update your TagBot.yml
to include issue comment triggers.
Please see this post on Discourse for instructions and more details.
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.