diff --git a/data/images/duck.png b/data/images/duck.png new file mode 100644 index 0000000..3572ee1 Binary files /dev/null and b/data/images/duck.png differ diff --git a/data/scripts/game.lua b/data/scripts/game.lua new file mode 100644 index 0000000..081d58b --- /dev/null +++ b/data/scripts/game.lua @@ -0,0 +1,78 @@ +-- called every frame, with constant delta time +local capture = false +local trig = require "trig" +local Vector3l = require "vector3" + + +local function Vector3(x, y, z) + if y == nil then + return {x = x, y = x, z = x} + end + return {x = x, y = y, z = z} +end + +local rot = 0 +local rot_spd = 0.05 + +local spd = 0.07 + +local pos = Vector3(0) + +local function Vector2(x, y) + if y == nil then + return {x = x, y = x} + end + return {x = x, y = y} +end + +local function wrap(value, min, max) + local range = max - min + if value == 0 then + return min + end + + local result = value - (range * math.floor((value - min) / range)) + if result == max then + return min + end + + return result +end + +local function b2n(value) + return value and 1 or 0 +end + +function game_tick() + -- ctx.initialization_needed is true first frame and every time dynamic reload is performed + if ctx.initialization_needed then + -- ctx.udata persists on reload + ctx.udata = {} + end + ctx.mouse_capture = capture + input_action{name="quit", control="SPACE"} + + input_action{name = "left", control = "A"} + input_action{name = "right", control = "D"} + input_action{name = "forward", control = "W"} + input_action{name = "back", control = "S"} + + if input_action_just_pressed{name = "quit"} then + if not capture then + capture = true + else + capture = false + end + end + local dir = draw_camera_from_principal_axes{position = pos, yaw = rot}.direction + dir.y = 0 + dir = trig.v3_normalized(dir) + + local rot_d = b2n(input_action_pressed{name = "right"}) - b2n(input_action_pressed{name = "left"}) + rot = rot + rot_d * rot_spd + + local mov_d = b2n(input_action_pressed{name = "forward"}) - b2n(input_action_pressed{name = "back"}) + pos = trig.v3_add(pos, trig.v3_mult(dir, spd * mov_d)) + + draw_billboard{position = Vector3(5, 0, 0), size = Vector2(1, 1), texture = "images/duck.png"} +end diff --git a/data/scripts/trig.lua b/data/scripts/trig.lua new file mode 100644 index 0000000..26bd0a8 --- /dev/null +++ b/data/scripts/trig.lua @@ -0,0 +1,38 @@ +local M = {} + +function M.v3_length_squared(v) + local x2 = v.x * v.x + local y2 = v.y * v.y + local z2 = v.z * v.z + + return x2 + y2 + z2 +end + +function M.v3_normalized(v) + local length = math.sqrt(M.v3_length_squared(v)) + local new_vec = { + x = v.x / length, + y = v.y / length, + z = v.z / length, + } + + return new_vec +end + +function M.v3_mult(v, f) + return { + x = v.x * f, + y = v.y * f, + z = v.z * f, + } +end + + +function M.v3_add(v1, v2) + return { + x = v1.x + v2.x, + y = v1.y + v2.y, + z = v1.z + v2.z, + } +end +return M \ No newline at end of file diff --git a/data/scripts/twnapi.lua b/data/scripts/twnapi.lua new file mode 100644 index 0000000..14d9aed --- /dev/null +++ b/data/scripts/twnapi.lua @@ -0,0 +1,60 @@ +error("townengine lua api file is not supposed to be imported!") +---@type { frame_number: number, frame_duration: number, fog_density: number, fog_color: { r: number, g: number, b: number, a: number }, resolution: { x: number, y: number }, mouse_position: { x: number, y: number }, mouse_movement: { x: number, y: number }, random_seed: number, debug: boolean, initialization_needed: boolean, mouse_capture: boolean, udata: table } +ctx = nil +---@alias Control '"A"'|'"B"'|'"C"'|'"D"'|'"E"'|'"F"'|'"G"'|'"H"'|'"I"'|'"J"'|'"K"'|'"L"'|'"M"'|'"N"'|'"O"'|'"P"'|'"Q"'|'"R"'|'"S"'|'"T"'|'"U"'|'"V"'|'"W"'|'"X"'|'"Y"'|'"Z"'|'"1"'|'"2"'|'"3"'|'"4"'|'"5"'|'"6"'|'"7"'|'"8"'|'"9"'|'"0"'|'"RETURN"'|'"ESCAPE"'|'"BACKSPACE"'|'"TAB"'|'"SPACE"'|'"MINUS"'|'"EQUALS"'|'"LEFTBRACKET"'|'"RIGHTBRACKET"'|'"BACKSLASH"'|'"NONUSHASH"'|'"SEMICOLON"'|'"APOSTROPHE"'|'"GRAVE"'|'"COMMA"'|'"PERIOD"'|'"SLASH"'|'"CAPSLOCK"'|'"F1"'|'"F2"'|'"F3"'|'"F4"'|'"F5"'|'"F6"'|'"F7"'|'"F8"'|'"F9"'|'"F10"'|'"F11"'|'"F12"'|'"PRINTSCREEN"'|'"SCROLLLOCK"'|'"PAUSE"'|'"INSERT"'|'"HOME"'|'"PAGEUP"'|'"DELETE"'|'"END"'|'"PAGEDOWN"'|'"RIGHT"'|'"LEFT"'|'"DOWN"'|'"UP"'|'"NUMLOCKCLEAR"'|'"KP_DIVIDE"'|'"KP_MULTIPLY"'|'"KP_MINUS"'|'"KP_PLUS"'|'"KP_ENTER"'|'"KP_1"'|'"KP_2"'|'"KP_3"'|'"KP_4"'|'"KP_5"'|'"KP_6"'|'"KP_7"'|'"KP_8"'|'"KP_9"'|'"KP_0"'|'"KP_PERIOD"'|'"NONUSBACKSLASH"'|'"APPLICATION"'|'"POWER"'|'"KP_EQUALS"'|'"F13"'|'"F14"'|'"F15"'|'"F16"'|'"F17"'|'"F18"'|'"F19"'|'"F20"'|'"F21"'|'"F22"'|'"F23"'|'"F24"'|'"EXECUTE"'|'"HELP"'|'"MENU"'|'"SELECT"'|'"STOP"'|'"AGAIN"'|'"UNDO"'|'"CUT"'|'"COPY"'|'"PASTE"'|'"FIND"'|'"MUTE"'|'"VOLUMEUP"'|'"VOLUMEDOWN"'|'"KP_COMMA"'|'"KP_EQUALSAS400"'|'"INTERNATIONAL1"'|'"INTERNATIONAL2"'|'"INTERNATIONAL3"'|'"INTERNATIONAL4"'|'"INTERNATIONAL5"'|'"INTERNATIONAL6"'|'"INTERNATIONAL7"'|'"INTERNATIONAL8"'|'"INTERNATIONAL9"'|'"LANG1"'|'"LANG2"'|'"LANG3"'|'"LANG4"'|'"LANG5"'|'"LANG6"'|'"LANG7"'|'"LANG8"'|'"LANG9"'|'"ALTERASE"'|'"SYSREQ"'|'"CANCEL"'|'"CLEAR"'|'"PRIOR"'|'"RETURN2"'|'"SEPARATOR"'|'"OUT"'|'"OPER"'|'"CLEARAGAIN"'|'"CRSEL"'|'"EXSEL"'|'"KP_00"'|'"KP_000"'|'"THOUSANDSSEPARATOR"'|'"DECIMALSEPARATOR"'|'"CURRENCYUNIT"'|'"CURRENCYSUBUNIT"'|'"KP_LEFTPAREN"'|'"KP_RIGHTPAREN"'|'"KP_LEFTBRACE"'|'"KP_RIGHTBRACE"'|'"KP_TAB"'|'"KP_BACKSPACE"'|'"KP_A"'|'"KP_B"'|'"KP_C"'|'"KP_D"'|'"KP_E"'|'"KP_F"'|'"KP_XOR"'|'"KP_POWER"'|'"KP_PERCENT"'|'"KP_LESS"'|'"KP_GREATER"'|'"KP_AMPERSAND"'|'"KP_DBLAMPERSAND"'|'"KP_VERTICALBAR"'|'"KP_DBLVERTICALBAR"'|'"KP_COLON"'|'"KP_HASH"'|'"KP_SPACE"'|'"KP_AT"'|'"KP_EXCLAM"'|'"KP_MEMSTORE"'|'"KP_MEMRECALL"'|'"KP_MEMCLEAR"'|'"KP_MEMADD"'|'"KP_MEMSUBTRACT"'|'"KP_MEMMULTIPLY"'|'"KP_MEMDIVIDE"'|'"KP_PLUSMINUS"'|'"KP_CLEAR"'|'"KP_CLEARENTRY"'|'"KP_BINARY"'|'"KP_OCTAL"'|'"KP_DECIMAL"'|'"KP_HEXADECIMAL"'|'"LCTRL"'|'"LSHIFT"'|'"LALT"'|'"LGUI"'|'"RCTRL"'|'"RSHIFT"'|'"RALT"'|'"RGUI"'|'"MODE"'|'"KBDILLUMTOGGLE"'|'"KBDILLUMDOWN"'|'"KBDILLUMUP"'|'"EJECT"'|'"SLEEP"'|'"APP1"'|'"APP2"'|'"AUDIOREWIND"'|'"AUDIOFASTFORWARD"'|'"SOFTLEFT"'|'"SOFTRIGHT"'|'"CALL"'|'"ENDCALL"'|'"LEFT_MOUSE"'|'"RIGHT_MOUSE"'|'"MIDDLE_MOUSE"'|'"X1"'|'"X2"' +---@param args { name: string, control: Control } +function input_action(args) end +---@param args { name: string } +---@return boolean +function input_action_pressed(args) end +---@param args { name: string } +---@return boolean +function input_action_just_pressed(args) end +---@param args { name: string } +---@return boolean +function input_action_just_released(args) end +---@param args { name: string } +---@return { x: number, y: number } +function input_action_position(args) end +---@param args { texture: string, rect: { x: number, y: number, w: number, h: number }, texture_region: { x: number, y: number, w: number, h: number }?, color: { r: number, g: number, b: number, a: number }?, rotation: number?, flip_x: boolean?, flip_y: boolean?, stretch: boolean? } +function draw_sprite(args) end +---@param args { rect: { x: number, y: number, w: number, h: number }, color: { r: number, g: number, b: number, a: number }? } +function draw_rectangle(args) end +---@param args { position: { x: number, y: number }, radius: number, color: { r: number, g: number, b: number, a: number }? } +function draw_circle(args) end +---@param args { string: string, position: { x: number, y: number }, height: number?, color: { r: number, g: number, b: number, a: number }?, font: string? } +function draw_text(args) end +---@param args { string: string, height: number?, font: string? } +---@return number +function draw_text_width(args) end +---@param args { texture: string, corners: { x: number, y: number }, rect: { x: number, y: number, w: number, h: number }, border_thickness: number?, color: { r: number, g: number, b: number, a: number }? } +function draw_nine_slice(args) end +---@param args { start: { x: number, y: number }, finish: { x: number, y: number }, thickness: number?, color: { r: number, g: number, b: number, a: number }? } +function draw_line(args) end +---@param args { texture: string, v0: { x: number, y: number, z: number }, v1: { x: number, y: number, z: number }, v2: { x: number, y: number, z: number }, uv0: { x: number, y: number }, uv1: { x: number, y: number }, uv2: { x: number, y: number }, c0: { r: number, g: number, b: number, a: number }?, c1: { r: number, g: number, b: number, a: number }?, c2: { r: number, g: number, b: number, a: number }? } +function draw_triangle(args) end +---@param args { texture: string, v0: { x: number, y: number, z: number }, v1: { x: number, y: number, z: number }, v2: { x: number, y: number, z: number }, v3: { x: number, y: number, z: number }, texture_region: { x: number, y: number, w: number, h: number }, color: { r: number, g: number, b: number, a: number }? } +function draw_quad(args) end +---@param args { texture: string, position: { x: number, y: number, z: number }, size: { x: number, y: number }, color: { r: number, g: number, b: number, a: number }?, cylindrical: boolean? } +function draw_billboard(args) end +---@param args { position: { x: number, y: number, z: number }, direction: { x: number, y: number, z: number }?, up: { x: number, y: number, z: number }?, fov: number?, zoom: number? } +function draw_camera(args) end +---@param args { position: { x: number, y: number, z: number }, roll: number?, pitch: number?, yaw: number?, fov: number?, zoom: number? } +---@return { direction: { x: number, y: number, z: number },up: { x: number, y: number, z: number } } +function draw_camera_from_principal_axes(args) end +---@param args { textures: string? } +function draw_skybox(args) end +---@param args { audio: string, channel: string?, loops: boolean?, volume: number?, panning: number? } +function audio_play(args) end +---@param args { channel: string, parameter: string, value: number } +function audio_parameter(args) end +---@param args { value: { x: number, y: number }, identity: string } +function log_vec2(args) end +---@param args { value: { x: number, y: number, z: number }, identity: string } +function log_vec3(args) end +---@param args { value: { x: number, y: number, w: number, h: number }, identity: string } +function log_rect(args) end +---@param args { profile: string } +function profile_start(args) end +---@param args { profile: string } +function profile_end(args) end diff --git a/data/twn.toml b/data/twn.toml new file mode 100644 index 0000000..c661911 --- /dev/null +++ b/data/twn.toml @@ -0,0 +1,27 @@ +# This file contains everything about the engine and your game that can be +# configured before it runs. +# +# Optional settings are commented out, with their default values shown. +# Invalid values in these settings will be ignored. + +# Data about your game as an application +[about] +title = "Quack" +developer = "Yag" +app_id = "quack" +dev_id = "yag" + +# Game runtime details +[game] +resolution = [ 640, 480 ] +background_color = [0, 0, 0, 1] +#debug = true + +# Engine tweaks. You probably don't need to change these +[engine] +#ticks_per_second = 60 # minimum of 8 +#keybind_slots = 3 # minimum of 1 +#texture_atlas_size = 2048 # minimum of 32 +#font_texture_size = 2048 # minimum of 1024 +#font_oversampling = 4 # minimum of 0 +#font_filtering = "linear" # possible values: "nearest", "linear"