From d6143951d8d540b9eb262ec8254b2ec319c71607 Mon Sep 17 00:00:00 2001 From: Stefan Stefanov Date: Tue, 31 Dec 2024 13:06:30 +0200 Subject: [PATCH] Added a sample sound and some config, added tween to the src --- .idea/.gitignore | 8 + .idea/OdinSdkConfig.xml | 13 + .idea/editor.xml | 580 +++++++++++++++++++++++++++++++++ .idea/libraries/Odin_SDK.xml | 9 + .idea/misc.xml | 21 ++ .idea/vcs.xml | 6 + .vscode/launch.json | 16 + .vscode/tasks.json | 19 ++ Makefile | 3 +- assets/sounds/pickup_sound.ogg | Bin 27699 -> 0 bytes src/main.odin | 90 ++--- tween/tween.odin | 239 ++++++++++++++ 12 files changed, 960 insertions(+), 44 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/OdinSdkConfig.xml create mode 100644 .idea/editor.xml create mode 100644 .idea/libraries/Odin_SDK.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/vcs.xml create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json delete mode 100644 assets/sounds/pickup_sound.ogg create mode 100644 tween/tween.odin diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/OdinSdkConfig.xml b/.idea/OdinSdkConfig.xml new file mode 100644 index 0000000..cfb49e8 --- /dev/null +++ b/.idea/OdinSdkConfig.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/.idea/editor.xml b/.idea/editor.xml new file mode 100644 index 0000000..1f0ef49 --- /dev/null +++ b/.idea/editor.xml @@ -0,0 +1,580 @@ + + + + + \ No newline at end of file diff --git a/.idea/libraries/Odin_SDK.xml b/.idea/libraries/Odin_SDK.xml new file mode 100644 index 0000000..fc0afde --- /dev/null +++ b/.idea/libraries/Odin_SDK.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..dd7d771 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,21 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..0034a38 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "cppvsdbg", + "request": "launch", + "name": "Debug", + "program": "${workspaceFolder}/game.exe", + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..7d71ffc --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,19 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "command": "make", + // "problemMatcher": [ + // "$msvc" + // ], + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} \ No newline at end of file diff --git a/Makefile b/Makefile index 61153b4..982bac1 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ run: - odin run src -out:game.exe -debug -use-separate-modules -sanitize:address + odin run src -out:game.exe -debug build: odin build src -out:game.exe -debug -use-separate-modules @@ -8,3 +8,4 @@ clean: rm *.exe rm -rf *.dSYM/ +all: build diff --git a/assets/sounds/pickup_sound.ogg b/assets/sounds/pickup_sound.ogg deleted file mode 100644 index 47648df75f83d69228b693d1f1521f5e10e7a4a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27699 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 OEr`L|F4PhMDE<%nq;|0Y diff --git a/src/main.odin b/src/main.odin index 545c8b0..95a8d04 100644 --- a/src/main.odin +++ b/src/main.odin @@ -27,7 +27,8 @@ world_mouse: rl.Vector2 screen_game_area: rl.Rectangle game_render_buffer_area := rl.Rectangle{0, 0, GAME_SCREEN_WIDTH, -GAME_SCREEN_HEIGHT} -pickup_sound := rl.LoadSound("assets/sounds/pickup_sound.ogg") +pickup_sound: rl.Sound +pickup_sound_data: []u8 : #load("../assets/sounds/pickup_sound.mp3") player_spritesheet_sprite: []u8 : #load("../assets/player.png") tomato_spritesheet_sprite: []u8 : #load("../assets/tomato.png") @@ -44,6 +45,18 @@ load_texture_from_memory :: proc(data: []u8) -> (texture: rl.Texture2D) { return texture } +load_sound_from_memory :: proc( + data: []u8, + sound_extension: cstring = ".mp3", +) -> ( + sound: rl.Sound, +) { + wav := rl.LoadWaveFromMemory(sound_extension, raw_data(data), auto_cast len(data)) + defer rl.UnloadWave(wav) + sound = rl.LoadSoundFromWave(wav) + return +} + sell_button_texture: rl.Texture2D background_texture: rl.Texture2D tile_dirt_dry_texture: rl.Texture2D @@ -64,11 +77,19 @@ tween_ctx_f32: t.TweenContext(f32) tween_ctx_vec2: t.TweenContext([2]f32) main :: proc() { - rl.SetConfigFlags({.VSYNC_HINT, .WINDOW_RESIZABLE, .WINDOW_HIGHDPI, .MSAA_4X_HINT}) + rl.SetConfigFlags({.VSYNC_HINT, .WINDOW_RESIZABLE, .MSAA_4X_HINT}) rl.InitWindow(1280, 720, "Raylib Minimal") rl.SetTargetFPS(rl.GetMonitorRefreshRate(rl.GetCurrentMonitor())) rl.InitAudioDevice() + if rl.IsAudioDeviceReady() { + fmt.println("Audio working!") + } else { + fmt.println("Audio borked!") + } + + pickup_sound = load_sound_from_memory(pickup_sound_data) + game_render_buffer = rl.LoadRenderTexture( auto_cast GAME_SCREEN_WIDTH, auto_cast GAME_SCREEN_HEIGHT, @@ -110,13 +131,13 @@ main :: proc() { rl.PlaySound(pickup_sound) - for !rl.WindowShouldClose() { - free_all(context.temp_allocator) - update() - draw() + if true {for !rl.WindowShouldClose() { + free_all(context.temp_allocator) + update() + draw() + } + } - - rl.UnloadRenderTexture(game_render_buffer) // Unload render texture rl.CloseAudioDevice() rl.CloseWindow() @@ -128,15 +149,16 @@ update :: proc() { t.tween_update(&tween_ctx_vec2, auto_cast rl.GetFrameTime()) // :scaling update + screen_width := rl.GetScreenWidth() + screen_height := rl.GetScreenHeight() screen_scale = min( - f32(rl.GetScreenWidth()) / GAME_SCREEN_WIDTH, - f32(rl.GetScreenHeight()) / GAME_SCREEN_HEIGHT, + f32(screen_width) / GAME_SCREEN_WIDTH, + f32(screen_height) / GAME_SCREEN_HEIGHT, ) mouse := rl.GetMousePosition() virtual_mouse := rl.Vector2 { - (mouse.x - (f32(rl.GetScreenWidth()) - (GAME_SCREEN_WIDTH * screen_scale)) * 0.5) / - screen_scale, - (mouse.y - (f32(rl.GetScreenHeight()) - (GAME_SCREEN_HEIGHT * screen_scale)) * 0.5) / + (mouse.x - (f32(screen_width) - (GAME_SCREEN_WIDTH * screen_scale)) * 0.5) / screen_scale, + (mouse.y - (f32(screen_height) - (GAME_SCREEN_HEIGHT * screen_scale)) * 0.5) / screen_scale, } virtual_mouse = rl.Vector2Clamp( @@ -385,35 +407,15 @@ update_tile :: proc(e: Entity, data: ^TileData) { update_animation(&data.animation) if data.has_plant && data.animation.done && data.plant_grown == false { data.plant_grown = true - player := handle_to_entity(player_handle) - if player != nil { - item := create_entity( - Entity { - pos = e.pos, - kind = .Item, - data = ItemData{id = data.plant_id, count = 3, texture = tomato_texture}, - }, - ) - tw := t.tween_to(&tween_ctx_vec2, &item.pos, player.pos) - tw.id = item.handle - tw.data = tw - tw.on_update = proc(ctx: ^t.TweenContext([2]f32), data: rawptr) { - player := handle_to_entity(player_handle) - if player != nil { - tween: ^t.Tween([2]f32) = transmute(^t.Tween([2]f32))data - tween.goal = player.pos - {TILE_SIZE, TILE_SIZE} - } - } - tw.on_complete = proc(ctx: ^t.TweenContext([2]f32), data: rawptr) { - tween: ^t.Tween([2]f32) = transmute(^t.Tween([2]f32))data - fmt.println("Done") - rl.PlaySound(pickup_sound) - e := handle_to_entity(tween.id) - if e != nil && e.kind == .Item { - destroy_entity(e) - } - } - } + data.has_plant = false + rl.PlaySound(pickup_sound) + item := create_entity( + Entity { + pos = e.pos, + kind = .Item, + data = ItemData{id = data.plant_id, count = 3, texture = tomato_texture}, + }, + ) } } @@ -444,7 +446,9 @@ draw_tile :: proc(e: Entity) { data, ok := e.data.(TileData) //rl.DrawRectangle(auto_cast e.pos.x, auto_cast e.pos.y, TILE_SIZE, TILE_SIZE, rl.BLACK) rl.DrawTextureV(tile_dirt_dry_texture, e.pos, rl.WHITE) - draw_animation(data.animation, e.pos) + if data.has_plant { + draw_animation(data.animation, e.pos) + } } draw_item :: proc(e: Entity) { data, ok := e.data.(ItemData) diff --git a/tween/tween.odin b/tween/tween.odin new file mode 100644 index 0000000..08e77b9 --- /dev/null +++ b/tween/tween.odin @@ -0,0 +1,239 @@ +package tween + +import "base:intrinsics" +import "core:math/ease" +import "core:time" + +TweenContext :: struct($T: typeid) { + tweens: [dynamic]Tween(T), +} + +Tween :: struct($T: typeid) { + value: ^T, + start: T, + diff: T, + goal: T, + delay: f64, // in seconds + duration: time.Duration, + progress: f64, + rate: f64, + type: ease.Ease, + inited: bool, + id: int, + + // callbacks, data can be set, will be pushed to callback + data: rawptr, // by default gets set to value input + on_start: proc(ctx: ^TweenContext(T), data: rawptr), + on_update: proc(ctx: ^TweenContext(T), data: rawptr), + on_complete: proc(ctx: ^TweenContext(T), data: rawptr), +} + +@(require_results) +context_init_f :: proc( + $T: typeid, +) -> TweenContext(T) where intrinsics.type_is_float(T) { + return {tweens = make([dynamic]Tween(T))} +} + +@(require_results) +context_init_v :: proc( + $T: typeid/[$N]$E, +) -> TweenContext(T) where intrinsics.type_is_float(E) { + return {tweens = make([dynamic]Tween(T))} +} + +context_init :: proc { + context_init_f, + context_init_v, +} + +// delete map content +context_destroy :: proc(ctx: TweenContext($T)) { + delete(ctx.tweens) +} + +// clear map content, stops all animations +context_clear :: proc(ctx: ^TweenContext($T)) { + clear(&ctx.tweens) +} + +// append / overwrite existing tween value to parameters +// rest is initialized in tween_init, inside update +// return value can be used to set callbacks +@(require_results) +tween_to :: proc( + ctx: ^TweenContext($T), + value: ^T, + goal: T, + type: ease.Ease = .Quadratic_Out, + duration: time.Duration = time.Second, + delay: f64 = 0, + id: int = 0, +) -> ( + tween: ^Tween(T), +) { + append(&ctx.tweens, Tween(T){}) + n := len(ctx.tweens) - 1 + tween = &ctx.tweens[n] + + tween^ = { + value = value, + goal = goal, + duration = duration, + delay = delay, + type = type, + data = value, + id = id, + } + + return +} + +// init internal properties +_tween_init :: proc(tween: ^Tween($T), duration: time.Duration) { + tween.inited = true + tween.start = tween.value^ + tween.diff = tween.goal - tween.value^ + s := time.duration_seconds(duration) + tween.rate = duration > 0 ? 1.0 / s : 0 + tween.progress = duration > 0 ? 0 : 1 +} + +_tween_init_f :: proc( + tween: ^Tween($T), + duration: time.Duration, +) where intrinsics.type_is_float(T) { + _tween_init(tween, duration) +} + +_tween_init_v :: proc( + tween: ^Tween($T/[$N]$E), + duration: time.Duration, +) where intrinsics.type_is_float(E) { + _tween_init(tween, duration) +} + +tween_init :: proc { + _tween_init_f, + _tween_init_v, +} + +_tween_interpolate :: proc(tween: ^Tween($T), dt, delay_remainder: f64) { + tween.progress += tween.rate * (dt + delay_remainder) + x := tween.progress >= 1 ? 1 : ease.ease(tween.type, tween.progress) + tween.value^ = tween.start + tween.diff * T(x) +} + +tween_interpolate_f :: proc( + tween: ^Tween($T), + dt, delay_remainder: f64, +) where intrinsics.type_is_float(T) { + _tween_interpolate(tween, dt, delay_remainder) +} + +tween_interpolate_v :: proc( + tween: ^Tween($T/[$N]$E), + dt, delay_remainder: f64, +) where intrinsics.type_is_float(E) { + _tween_interpolate(tween, dt, delay_remainder) +} + +tween_interpolate :: proc { + tween_interpolate_f, + tween_interpolate_v, +} + +// update all tweens, wait for their delay if one exists +// calls callbacks in all stages, when they're filled +// deletes tween from the map after completion +_tween_update :: proc(ctx: ^TweenContext($T), dt: f64) { + for &tween in ctx.tweens { + delay_remainder := f64(0) + + // Update delay if necessary. + if tween.delay > 0 { + tween.delay -= dt + + if tween.delay < 0 { + // We finished the delay, but in doing so consumed part of this frame's `dt` budget. + // Keep track of it so we can apply it to this tween without affecting others. + delay_remainder = tween.delay + // We're done with this delay. + tween.delay = 0 + } + } + + // We either had no delay, or the delay has been consumed. + if tween.delay <= 0 { + if !tween.inited { + tween_init(&tween, tween.duration) + + if tween.on_start != nil { + tween.on_start(ctx, tween.data) + } + } + + // If part of the `dt` budget was consumed this frame, then `delay_remainder` will be + // that remainder, a negative value. Adding it to `dt` applies what's left of the `dt` + // to the tween so it advances properly, instead of too much or little. + tween_interpolate(&tween, dt, delay_remainder) + // tween.progress += tween.rate * (dt + delay_remainder) + // x := tween.progress >= 1 ? 1 : ease(tween.type, tween.progress) + // tween.value^ = tween.start + tween.diff * T(x) + + if tween.on_update != nil { + tween.on_update(ctx, tween.data) + } + + if tween.progress >= 1 { + // append keys to array that will be deleted after the loop + + if tween.on_complete != nil { + tween.on_complete(ctx, tween.data) + } + } + } + } +} + +tween_update_f :: proc(ctx: ^TweenContext($T), dt: f64) where intrinsics.type_is_float(T) { + _tween_update(ctx, dt) +} + +tween_update_v :: proc(ctx: ^TweenContext($T/[$N]$E), dt: f64) where intrinsics.type_is_float(E) { + _tween_update(ctx, dt) +} + +tween_update :: proc { + tween_update_v, + tween_update_f, +} + +// stop a specific key inside the map +// returns true when it successfully removed the key +// @(require_results) +tween_stop :: proc(ctx: ^TweenContext($T), id: int) -> bool { + removed_tweens := false + for i := 0; i < len(ctx.tweens); { + if tween.id == id { + unordered_remove(&ctx.tweens, i) + removed_tweens = true + } else { + i += 1 + } + } + + return false +} + +// Returns the first tween animation with that id +// If no tween exists with the given id, will return 0 +@(require_results) +tween_time_left :: proc(flux: TweenContext($T), id: int) -> f64 { + for tween in ctx.tweens { + if tween.id == id { + return ((1 - tween.progress) * tween.rate) + tween.delay + } + } + return 0 +}