Aroma 基于 Lua 的游戏开发框架
Aroma 是基于 Chrome's Native Client 的游戏开发框架,你可以使用 Lua 编程语言来编写游戏,并通过 Chrome Web Store 进行发布。
如何工作
原生客户端文件分布 .nexe
二进制文件,编译 64位和32位电脑。 Aroma 是一个编译 .nexe
文件,年代 上传到你的服务器后可以使用。 所有你需要做的就是上传你的游戏与Aroma。
重用你的浏览器
为了保持 .nexe
二进制小,Aroma重用你的浏览器 没有根据附加的库完成许多任务。 之类的东西 呈现字体和解码图像的处理Canvas标签。 加载游戏资源的透明变成了HTTP请求给你切断。
异步加载
Aroma 从网上加载你所有的游戏代码。 你通常将上传代码与 Aroma 年代 .nexe
和 .js
文件。 这使您能够迅速 部署更改,而无需重新编译。
如果你做过Web编程你可能熟悉 异步请求的服务器获取资源提供一些 一个回调函数。 另一方面当加载代码在 Lua 中你一般 写点东西同步:
require "mygame.enemy"
Aroma将这个调用转换为异步请求的浏览器, 阻塞的执行游戏,直到获取资源。 结合浏览器提供的缓存,这使得加载代码 Web 愉快。
Aroma也有能力为了一起批处理异步请求更快地执行它们。
Aroma JavaScript API
aroma.js
The JavaScript API manages the creation and existence of your game in the browser. JavaScript is used to create the Aroma viewport and start the execution of your game.
You can use this API to set up the size of your game viewport and handle any text sent to standard out or standard error.
Create a game like so:
<script type="text/javascript" src="aroma.js"></script>
<div id="game_container"></div>
<script type="text/javascript">
var container = document.getElementById("game_container");
var game = new Aroma(container, 640, 480, {
loaded: function() {
alert("Aroma is ready!");
}
});
</script>
The third argument of the Aroma
constructor is an object of functions for various events. In this example we provide a function for the loaded
event. The loaded event fires when Aroma’s binary has finished downloading.
After Aroma has loaded it will by default try to load main
, which involves searching for main.lua
in the current directory.
In this example we overwrite the default load behavior and use the execute
method to run arbitrary Lua in Aroma.
var game = new Aroma(container, 640, 480, {
loaded: function() {
game.execute("function aroma.draw() aroma.graphics.print('Hello World!', 10, 10) end");
}
});
The example above is one of the simplest examples of an Aroma game.
By default, standard out is sent into Chrome’s console.log
and standard error is sent into console.error
. This means if we use the Lua function print
we will see the output in in the console. Likewise, if your code crashes the error information will also show up in the console. (You can open up the console by clicking on the wrench icon and going to Tools > JavaScript Console)
Aroma
Controls the game instance and message passing between the game and the browser.
Aroma constructor
aroma = new Aroma ( container , width , height , event_handlers )
Creates Aroma frame and Lua environment. Causes the nexe
to be downloaded if it hasn’t been already.
container
— A DOM node where the game will be placed. Can also be a string which represents an id of a DOM node.width
— Width of the frame in pixels.height
— Height of the frame in pixels.event_handlers
— An object containing functions for certain named events.
Possible event handlers include:
"loaded"
— Called when the frame is ready to execute Lua."std_out"
— Called whenever Lua writes to standard out. Recieves one argument, what was written."std_err"
— Same as above, except for standard error.
By default, std_out
is set to write to console.log
and std_err
is set to write to console.err
.
The default loaded event executes the following Lua code:
require "main"
if aroma and aroma.load then
aroma.load()
end
var game = new Aroma("game_container", 640, 480, {
loaded: function() {
game.execute("print 'hello world!'");
},
std_out: function(msg) {
alert(msg);
}
});
execute
game.execute ( lua_code )
Takes one argument, lua_code
, a string of Lua code that will be executed, Will reset all game state. This should only be called when you want to run a new game.
Aroma Lua API
nacl
Interface to the NaCl container.
prefetch
nacl.prefetch ( resource_table )
Causes Aroma to block and fetch a collection of resources at once. The browser will download all the resources in parallel, which will take much less time than requesting them individually.
This will not return any of the resources, it will only cache their values on the client so when you do ask for the request later it will be available without blocking the game.
nacl.prefetch({
images = {
"thing.png",
"world.png",
}
})
track_event
nacl.track_event ( category , action , label , value , interactive )
This will attempt to send a custom event to Google Analytics. Only works if Google Analytics is available on the game page.
if player.beat_game then
nacl.track_event("my_game", "player_event", "win")
end
aroma
The aroma
object serves two parts. It contains all Aroma submodules, which are also listed on this page, and it is where callback functions are assigned.
Callbacks are functions that you create and assign to the aroma
object. They will be called by the engine when certain events happen.
You only need to assign these callback functions when if you are using them, leaving them out is perfectly okay. You should never need to call these functions manually (but you can).
Here is the complete list of callbacks:
draw
aroma.draw ( )
Where all of your drawing code should go.
function aroma.draw()
aroma.graphics.print("hello world", 10, 10)
end
focus
aroma.focus ( has_focus )
Called when the focus of the game window has changed
function aroma.focus(has_focus)
print("Focus changed:", has_focus)
end
keypressed
aroma.keypressed ( key_name , key_code )
Called when a key is pressed down. Given two arguments:
key_name
— A string representing the name of the key pressedkey_code
— An integer representing the code of the key
function aroma.keypressed(key_name, key_code)
print("Key pressed:", key_name, key_code)
end
keyreleased
aroma.keyreleased ( key_name , key_code )
Callen when a key is released.
Arguments are the same as aroma.keypressed.
update
aroma.update ( dt )
Where game state updates should go. Takes one argument, dt
, the amount of time in seconds since the last frame.
You should not draw from this function, nothing will show up.
function aroma.update(dt)
player.x = player.x + speed * dt
end
aroma.graphics
Functions responsible for drawing things on the screen or changing the state of drawing.
drawing
- draw
- drawq
- rectangle
constructors
- newFont
- newImage
- newImageFont
- newQuad
- newShader
transformations
- pop
- push
- rotate
- scale
- translate
color
- setBackgroundColor
- getColor
- setColor
misc
- reset
- setDefaultShader
- setFont
- getFont
- getHeight
- setLineWidth
- getWidth
draw
aroma.graphics.draw ( drawable , x , y , [rotate] , [scale_x] , [scale_y] , [origin_x] , [origin_y] )
Draws a drawable object on the screen. Right now the only drawable objects are images.
rotate
is clockwise rotation in degrees.
origin_x
and origin_y
can be used to control the origin of rotation.
drawq
aroma.graphics.drawq ( drawable , quad , x , y , [rotate] , [scale_x] , [scale_y] , [origin_x] , [origin_y] )
Similar to aroma.graphics.draw, but takes a Quad as second argument.
A Quad can be used to only draw a portion of an image. Useful for drawing sprites from a single image.
local img = aroma.graphics.newImage("hi.png")
local q = aroma.graphics.newQuad(5, 5, 10, 10, img:getWidth(), img:getHeight())
-- draws the part of the image specified by the quad at 10, 10
function aroma.draw()
aroma.graphics.drawq(img, q, 10, 10)
end
newFont
font = aroma.graphics.newFont ( font_name , [alphabet] )
Creates a new font and returns it. Fonts are rendered by the browser in a <canvas>
tag and then passed back to Aroma.
font_name
must be a valid CSS font value.
alphabet
is an optional string whose characters will be the glyphs available in the font. Defaults to all numbers, letters, and symbols on an English keyboard.
Custom fonts can be made available by embedding fonts into the stylesheet of the host page using @font-face
.
local monospace = aroma.graphics.newFont("32px monospace")
-- only numbers can be written with this font
local numbers = aroma.graphics.newFont("10pt serif", "0987654321")
newImage
image = aroma.graphics.newImage ( image_url )
Loads and image by url and returns it as an Image object.
Images can be drawn to the screen using aroma.graphics.draw.
local image = aroma.graphics.newImage("hello.png")
function aroma.draw()
aroma.graphics.draw(image, 10, 10)
end
newImageFont
font = aroma.graphics.newImageFont ( image , alphabet )
Creates a new font from an image and returns it. Unlike aroma.graphics.newFont, letters are extracted from a bitmap instead a typeface from the browser.
image
— An image url or an ImageData object.alphabet
— A string of letters as they appear in the image.
The image must be formatted as a single row of letters where each letter is separated by a spacer color:
The spacer color is always the top left color in the image, so place a spacer column as the leftmost thing in the image. The spacer column can be any width.
The rightmost part of the image must also be a spacer column, or the last letter will be left out.
-- write some text with the font above
local number_font = aroma.graphics.newImageFont("numbers.png", " 1234567890")
aroma.graphics.setFont(number_font)
function aroma.draw()
aroma.graphics.print("1337", 10, 10)
end
newQuad
quad = aroma.graphics.newQuad ( x , y , width , height , source_width , source_height )
Creates a new Quad
for use with aroma.graphics.drawq.
source_width
and source_height
are typically the width and height of the image the quad is being used on.
x
, y
, width
, height
represent the rectangle that should be drawn from the image.
newShader
shader = aroma.graphics.newShader ( vertex_shader_source , fragment_shader_source )
Create a new shader.
pop
aroma.graphics.pop ( )
Pops the current transformation off the transformation stack.
aroma.graphics.print ( [font] , text , x , y , [rotate] , [scale_x] , [scale_y] , [origin_x] , [origin_y] )
Draws text on the screen. If font
is not provided, the default font will be used. See aroma.graphics.setFont.
push
aroma.graphics.push ( )
Copies and pushes the current transformation onto the transformation stack.
rectangle
aroma.graphics.rectangle ( [render_style] , x , y , width , height )
Draws a rectangle on the screen.
The color of the rectangle is the current color. See aroma.graphics.setColor.
render_style
is an optional string that determines how the rectangle is drawn. "fill"
is the default. Must be one of the following:
"fill"
"line"
reset
aroma.graphics.reset ( )
Resets graphics state to default. This includes:
- Background color
- Drawing color
- Blend mode
rotate
aroma.graphics.rotate ( deg )
Modifies the current transformation to rotate all draws by deg
degrees.
The center of origin is at (0,0)
. It is helpful to combine this with translation control the center of origin relative to the object being drawing.
scale
aroma.graphics.scale ( sx , sy )
Modifies the current transformation by scaling all draws by sx
and sy
.
setBackgroundColor
aroma.graphics.setBackgroundColor ( red , green , blue , alpha )
Set the color the screen is cleared to after every frame.
getColor
red , green , blue , alpha = aroma.graphics.getColor ( )
Gets the current color for drawing.
setColor
aroma.graphics.setColor ( red , green , blue , [alpha] )
Set the current color for drawing.
-- draw a red rectangle
function aroma.draw()
aroma.graphics.setColor(255,0,0)
aroma.graphics.rectangle(10,10, 50,50)
end
setDefaultShader
aroma.graphics.setDefaultShader ( shader )
Replaces the shader responsible for all drawing. Be careful with this. If the shader does not work in a specific way then nothing may be drawn or Aroma may crash.
shader
must be a shader created with aroma.graphics.newShader.
setFont
aroma.graphics.setFont ( font )
Sets the current font. font
must be a font return by aroma.graphics.newFont.
getFont
font = aroma.graphics.getFont ( )
Gets the current font.
getHeight
height = aroma.graphics.getHeight ( )
Gets the height of the viewport in pixels.
setLineWidth
aroma.graphics.setLineWidth ( width )
Set the width of lines lines drawn.
getWidth
width = aroma.graphics.getWidth ( )
Gets the width of the viewport in pixels.
translate
aroma.graphics.translate ( tx , tx )
Modifies the current transformation by translating all draws by tx
and ty
.
function aroma.draw()
aroma.graphics.translate(20, 20)
-- will be drawn at 25, 25
aroma.graphics.rectangle(5, 5, 10, 10)
end
Image
Images can be drawn with
getWidth
width = image:getWidth ( )
Gets the width of the image.
getHeight
height = image:getHeight ( )
Gets the height of the image.
setWrap
image:setWrap ( horiz_wrap , vert_wrap )
Sets the wrapping mode of the image when overdrawn (by something like drawq
). By default wrap is set to "clamp"
.
Possible values for each:
"clamp"
— the color at the edge of the texture will be used to fill the extra space."repeat"
— The texture will repeat to fill extra space.
setFilter
image:setFilter ( min_filter , mag_filter )
Sets how images are filtered when they are scaled. By default wrap is set to "linear"
for both min and mag.
min_filter
— applied when the image is rendered smaller than its original dimensions.mag_filter
— applied when the image is rendered larger its original dimensions.
Posible values include:
"linear"
— The colors of nearby pixels are blended, creates a smoothing effect."nearest"
— no blending is done. This is the best filter to use when working with pixel art.
Font
Represents a loaded font. Created with aroma.graphics.newFont.
Can be drawn with setFont or print.
Quad
Represents a rectangular portion of something. Created with aroma.graphics.newQuad.
Drawn with aroma.graphics.drawq.
flip
quad:flip ( x , y )
x
— Flips Quad horizontally if truey
— Flips Quad vertically if true
aroma.audio
Functions for working with sound.
newSource
audio = aroma.audio.newSource ( source_url , [source_type] )
Loads a new source by url. Returns an AudioSource.
source_type
is an optional value that determines how the sound is loaded. "static"
is the default. The following types are valid:
"static"
— The function will block until the entire audio source is loaded into memory and ready be played. Uses the Web Audio API. Suitable for short samples such as sound effects."streaming"
— Uses the<audio>
tag. The function will not wait for the entire file to download, will only verify that the file exists. Playback of the sound might be delayed. Can also be unreliable. Suitable for background music.
local bg = aroma.audio.newSource("game/theme.ogg", "streaming")
local effect = aroma.audio.newSource("game/shoot.ogg")
bg:play() -- not guaranteed to play immediately, could still be downloading
effect:play() -- guaranteed to play
AudioSource
A static or stremaing audio srouce. Created with aroma.audio.newSource.
play
source:play ( )
pause
source:pause ( )
stop
source:stop ( )
setLooping
source:setLooping ( looping )
aroma.image
Functions for manipulating images and image data.
newImageData
data = aroma.image.newImageData ( image_url )
aroma.keyboard
Functions for querying information about the keyboard.
isDown
is_down = aroma.keyboard.isDown ( key_name )
Checks if a key is currently pressed down.
function aroma.update()
if aroma.keyboard.isDown(" ") then
print("Space is pressed!")
end
end
aroma.timer
Functions relating to the internal timer.
getFPS
fps = aroma.timer.getFPS ( )
Gets the frames per second of the game.
getTime
time = aroma.timer.getTime ( )
Gets the value of the internal timer in seconds. The value by itself is meaningless but it useful when compared against other times.
相关链接
- 项目主页:http://leafo.net/aroma/
- Github地址:https://github.com/leafo/aroma
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论