Compare commits
11 Commits
acc91fd5a8
...
be888397e4
| Author | SHA1 | Date | |
|---|---|---|---|
| be888397e4 | |||
|
|
4cf96e771f | ||
|
|
759d3ff61a | ||
|
|
3f4dfdc483 | ||
|
|
c8e40f3845 | ||
|
|
8853ece16a | ||
|
|
75d4e7fc9f | ||
|
|
31630dded8 | ||
|
|
c880765945 | ||
|
|
e5415bcb6e | ||
|
|
a6c1b96d0a |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -405,3 +405,4 @@ Makefile
|
|||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
*.swn
|
*.swn
|
||||||
|
/build/compile_commands.json
|
||||||
|
|||||||
38
.vscode/launch.json
vendored
38
.vscode/launch.json
vendored
@@ -8,7 +8,6 @@
|
|||||||
"name": "Debug",
|
"name": "Debug",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/bin/Debug/${workspaceFolderBasename}.exe",
|
|
||||||
"args": [],
|
"args": [],
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
@@ -23,7 +22,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"windows": {
|
"windows": {
|
||||||
"miDebuggerPath": "gdb.exe",
|
"program": "${workspaceFolder}/bin/Debug/${workspaceFolderBasename}.exe",
|
||||||
|
"miDebuggerPath": "gdb.exe"
|
||||||
},
|
},
|
||||||
"osx": {
|
"osx": {
|
||||||
"program": "${workspaceFolder}/bin/Debug/${workspaceFolderBasename}",
|
"program": "${workspaceFolder}/bin/Debug/${workspaceFolderBasename}",
|
||||||
@@ -36,7 +36,38 @@
|
|||||||
"preLaunchTask": "build debug"
|
"preLaunchTask": "build debug"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Run",
|
"name": "Debug NoPremake",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"args": [],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"windows": {
|
||||||
|
"program": "${workspaceFolder}/bin/Debug/${workspaceFolderBasename}.exe",
|
||||||
|
"miDebuggerPath": "gdb.exe"
|
||||||
|
},
|
||||||
|
"osx": {
|
||||||
|
"program": "${workspaceFolder}/bin/Debug/${workspaceFolderBasename}",
|
||||||
|
"MIMode": "lldb"
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"program": "${workspaceFolder}/bin/Debug/${workspaceFolderBasename}",
|
||||||
|
"miDebuggerPath": "/usr/bin/gdb",
|
||||||
|
},
|
||||||
|
"preLaunchTask": "build debug no premake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Run Release",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"args": [],
|
"args": [],
|
||||||
@@ -44,7 +75,6 @@
|
|||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"environment": [],
|
"environment": [],
|
||||||
"externalConsole": false,
|
"externalConsole": false,
|
||||||
"program": "${workspaceFolder}/bin/Release/${workspaceFolderBasename}.exe",
|
|
||||||
"MIMode": "gdb",
|
"MIMode": "gdb",
|
||||||
"windows": {
|
"windows": {
|
||||||
"program": "${workspaceFolder}/bin/Release/${workspaceFolderBasename}.exe",
|
"program": "${workspaceFolder}/bin/Release/${workspaceFolderBasename}.exe",
|
||||||
|
|||||||
45
.vscode/tasks.json
vendored
45
.vscode/tasks.json
vendored
@@ -24,6 +24,26 @@
|
|||||||
],
|
],
|
||||||
"dependsOn":["UpdateMake"]
|
"dependsOn":["UpdateMake"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "build debug no premake",
|
||||||
|
"type": "process",
|
||||||
|
"command": "make",
|
||||||
|
"windows": {
|
||||||
|
"command": "mingw32-make.exe",
|
||||||
|
},
|
||||||
|
"osx": {
|
||||||
|
"args": [
|
||||||
|
"config=debug_arm64"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"problemMatcher": [
|
||||||
|
"$gcc"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "build release",
|
"label": "build release",
|
||||||
"type": "process",
|
"type": "process",
|
||||||
@@ -95,7 +115,30 @@
|
|||||||
"osx": {
|
"osx": {
|
||||||
"command": "premake5.osx"
|
"command": "premake5.osx"
|
||||||
},
|
},
|
||||||
"group": "build"
|
"group": "build",
|
||||||
|
"dependsOn": ["Generate compile_commands.json"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Generate compile_commands.json",
|
||||||
|
"type": "process",
|
||||||
|
"command": "./premake5",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}/build/"
|
||||||
|
},
|
||||||
|
"args": [
|
||||||
|
"ecc"
|
||||||
|
],
|
||||||
|
"windows": {
|
||||||
|
"command": "./premake5.exe"
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"command": "./premake5"
|
||||||
|
},
|
||||||
|
"osx": {
|
||||||
|
"command": "premake5.osx"
|
||||||
|
},
|
||||||
|
"group": "build",
|
||||||
|
"problemMatcher": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
58
README.md
58
README.md
@@ -2,15 +2,36 @@
|
|||||||
A simple cross platform template for setting up a project with the bleeding edge raylib code.
|
A simple cross platform template for setting up a project with the bleeding edge raylib code.
|
||||||
Works with C or C++.
|
Works with C or C++.
|
||||||
|
|
||||||
|
# Basic Setup
|
||||||
|
Download this repository to get started.
|
||||||
|
|
||||||
|
You can download the zip file of the repository from the Green Code button on github. This is the simplest way to get the template to start from.
|
||||||
|
Once you have downloaded the template, rename it to your project name.
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
Clone the repository with git, from the url
|
||||||
|
```
|
||||||
|
https://github.com/raylib-extras/raylib-quickstart.git
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using a command line git client you can use the command below to download and rename the template in one step
|
||||||
|
```
|
||||||
|
git clone https://github.com/raylib-extras/raylib-quickstart.git [name-for-your-project-here]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Naming projects
|
||||||
|
* Replace the placeholder with your desired project name when running the git clone command above.
|
||||||
|
* __Do not name your game project 'raylib', it will conflict with the raylib library.__
|
||||||
|
* If you have used custom game name with __git clone__, there is no need to rename it again.
|
||||||
|
|
||||||
|
|
||||||
## Supported Platforms
|
## Supported Platforms
|
||||||
Quickstart supports the main 3 desktop platforms:
|
Quickstart supports the main 3 desktop platforms:
|
||||||
* Windows
|
* Windows
|
||||||
* Linux
|
* Linux
|
||||||
* MacOS
|
* MacOS
|
||||||
|
|
||||||
# Naming projects
|
|
||||||
Do not name your game project 'raylib', it will conflict with the raylib library.
|
|
||||||
|
|
||||||
# VSCode Users (all platforms)
|
# VSCode Users (all platforms)
|
||||||
*Note* You must have a compiler toolchain installed in addition to vscode.
|
*Note* You must have a compiler toolchain installed in addition to vscode.
|
||||||
|
|
||||||
@@ -23,9 +44,10 @@ Do not name your game project 'raylib', it will conflict with the raylib library
|
|||||||
# Windows Users
|
# Windows Users
|
||||||
There are two compiler toolchains available for windows, MinGW-W64 (a free compiler using GCC), and Microsoft Visual Studio
|
There are two compiler toolchains available for windows, MinGW-W64 (a free compiler using GCC), and Microsoft Visual Studio
|
||||||
## Using MinGW-W64
|
## Using MinGW-W64
|
||||||
|
* Rename the folder to your game name
|
||||||
* Double click the `build-MinGW-W64.bat` file
|
* Double click the `build-MinGW-W64.bat` file
|
||||||
* CD into the folder in your terminal
|
* CD into the folder in your terminal
|
||||||
* if you are usiing the W64devkit and have not added it to your system path environment variable, you must use the W64devkit.exe terminal, not CMD.exe
|
* if you are using the W64devkit and have not added it to your system path environment variable, you must use the W64devkit.exe terminal, not CMD.exe
|
||||||
* If you want to use cmd.exe or any other terminal, please make sure that gcc/mingw-W64 is in your path environment variable.
|
* If you want to use cmd.exe or any other terminal, please make sure that gcc/mingw-W64 is in your path environment variable.
|
||||||
* run `make`
|
* run `make`
|
||||||
* You are good to go
|
* You are good to go
|
||||||
@@ -34,7 +56,9 @@ There are two compiler toolchains available for windows, MinGW-W64 (a free compi
|
|||||||
Make sure you have a modern version of MinGW-W64 (not mingw).
|
Make sure you have a modern version of MinGW-W64 (not mingw).
|
||||||
The best place to get it is from the W64devkit from
|
The best place to get it is from the W64devkit from
|
||||||
https://github.com/skeeto/w64devkit/releases
|
https://github.com/skeeto/w64devkit/releases
|
||||||
|
|
||||||
or the version installed with the raylib installer
|
or the version installed with the raylib installer
|
||||||
|
|
||||||
#### If you have installed raylib from the installer
|
#### If you have installed raylib from the installer
|
||||||
Make sure you have added the path
|
Make sure you have added the path
|
||||||
|
|
||||||
@@ -45,12 +69,14 @@ To your path environment variable so that the compiler that came with raylib can
|
|||||||
DO NOT INSTALL ANOTHER MinGW-W64 from another source such as msys2, you don't need it.
|
DO NOT INSTALL ANOTHER MinGW-W64 from another source such as msys2, you don't need it.
|
||||||
|
|
||||||
## Microsoft Visual Studio
|
## Microsoft Visual Studio
|
||||||
|
* Rename the folder to your game name
|
||||||
* Run `build-VisualStudio2022.bat`
|
* Run `build-VisualStudio2022.bat`
|
||||||
* double click the `.sln` file that is generated
|
* double click the `.sln` file that is generated
|
||||||
* develop your game
|
* develop your game
|
||||||
* you are good to go
|
* you are good to go
|
||||||
|
|
||||||
# Linux Users
|
# Linux Users
|
||||||
|
* Rename the folder to your game name
|
||||||
* CD into the build folder
|
* CD into the build folder
|
||||||
* run `./premake5 gmake`
|
* run `./premake5 gmake`
|
||||||
* CD back to the root
|
* CD back to the root
|
||||||
@@ -58,6 +84,7 @@ DO NOT INSTALL ANOTHER MinGW-W64 from another source such as msys2, you don't ne
|
|||||||
* you are good to go
|
* you are good to go
|
||||||
|
|
||||||
# MacOS Users
|
# MacOS Users
|
||||||
|
* Rename the folder to your game name
|
||||||
* CD into the build folder
|
* CD into the build folder
|
||||||
* run `./premake5.osx gmake`
|
* run `./premake5.osx gmake`
|
||||||
* CD back to the root
|
* CD back to the root
|
||||||
@@ -94,6 +121,13 @@ If you need to build for a different OpenGL version than the default (OpenGL 3.3
|
|||||||
## For OpenGLES 3.0
|
## For OpenGLES 3.0
|
||||||
`--graphics=opengles3`
|
`--graphics=opengles3`
|
||||||
|
|
||||||
|
## For Software Rendering
|
||||||
|
`--graphics=software`
|
||||||
|
|
||||||
|
*Note*
|
||||||
|
Sofware rendering does not work with glfw, use Win32 or SDL platforms
|
||||||
|
`--backend=win32`
|
||||||
|
|
||||||
# Adding External Libraries
|
# Adding External Libraries
|
||||||
|
|
||||||
Quickstart is intentionally minimal — it only includes what is required to compile and run a basic raylib project.
|
Quickstart is intentionally minimal — it only includes what is required to compile and run a basic raylib project.
|
||||||
@@ -123,19 +157,5 @@ Different libraries will have different dependencies on different platforms.
|
|||||||
|
|
||||||
|
|
||||||
# License
|
# License
|
||||||
Copyright (c) 2020-2025 Jeffery Myers
|
Raylib-Quickstart by Jeffery Myers is marked with CC0 1.0. To view a copy of this license, visit https://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
|
||||||
This software is provided "as-is", without any express or implied warranty. In no event
|
|
||||||
will the authors be held liable for any damages arising from the use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any purpose, including commercial
|
|
||||||
applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not claim that you
|
|
||||||
wrote the original software. If you use this software in a product, an acknowledgment
|
|
||||||
in the product documentation would be appreciated but is not required.
|
|
||||||
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
|
||||||
as being the original software.
|
|
||||||
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|||||||
29
build/ecc/LICENSE.md
Normal file
29
build/ecc/LICENSE.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2022, Matvey Bystrin
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
49
build/ecc/README.md
Normal file
49
build/ecc/README.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Export Compile Commands - ECC
|
||||||
|
Module implementing support for [JSON Compilation Database Format
|
||||||
|
Specification](https://clang.llvm.org/docs/JSONCompilationDatabase.html).
|
||||||
|
|
||||||
|
This is an alternative to
|
||||||
|
[tarruda's](https://github.com/tarruda/premake-export-compile-commands) module,
|
||||||
|
which does one simple thing - generates one `compile_commands.json` file for
|
||||||
|
your project.
|
||||||
|
|
||||||
|
Tested with clangd-13.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
Premake 5.0.0 or later.
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
Download premake-ecc and place it near your premake5.lua script. Then require it
|
||||||
|
from your premake script
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require "ecc/ecc"
|
||||||
|
```
|
||||||
|
|
||||||
|
After you simply can call:
|
||||||
|
|
||||||
|
```
|
||||||
|
premake5 ecc
|
||||||
|
```
|
||||||
|
|
||||||
|
Moldule will generate **one** `compile_commands.json` file near your main
|
||||||
|
premake script. During generation it will use the default config (the first one
|
||||||
|
you have specified in script). If you want to select specific config just pass
|
||||||
|
it's name with command line option:
|
||||||
|
|
||||||
|
```
|
||||||
|
premake5 --config=release ecc
|
||||||
|
```
|
||||||
|
|
||||||
|
Careful! `config` option case sensitive! If there is no config passed via
|
||||||
|
command line, module will choose the default one.
|
||||||
|
|
||||||
|
Note: if you want to embed this module into your premake build follow
|
||||||
|
the [manual](https://premake.github.io/docs/Embedding-Modules/)
|
||||||
|
|
||||||
|
## Future plans
|
||||||
|
- Add unit tests
|
||||||
|
|
||||||
|
## Alternatives
|
||||||
|
- [export-compile-commands](https://github.com/tarruda/premake-export-compile-commands)
|
||||||
|
- [bear](https://github.com/rizsotto/Bear)
|
||||||
4
build/ecc/_manifest.lua
Normal file
4
build/ecc/_manifest.lua
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
return {
|
||||||
|
"_preload.lua",
|
||||||
|
"ecc.lua"
|
||||||
|
}
|
||||||
35
build/ecc/_preload.lua
Normal file
35
build/ecc/_preload.lua
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
local p = premake
|
||||||
|
|
||||||
|
newoption {
|
||||||
|
trigger = "config",
|
||||||
|
value = "CFG",
|
||||||
|
description = "Select config for export compile_commands.json"
|
||||||
|
}
|
||||||
|
|
||||||
|
newaction {
|
||||||
|
trigger = "ecc",
|
||||||
|
shortname = "Export compile commands",
|
||||||
|
description = "Export compile_commands.json for language server",
|
||||||
|
toolset = "gcc",
|
||||||
|
|
||||||
|
valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" },
|
||||||
|
valid_languages = { "C", "C++" },
|
||||||
|
valid_tools = {
|
||||||
|
cc = { "clang", "gcc" }
|
||||||
|
},
|
||||||
|
|
||||||
|
onStart = function()
|
||||||
|
p.indent(" ")
|
||||||
|
end,
|
||||||
|
|
||||||
|
execute = function()
|
||||||
|
local dir = {}
|
||||||
|
dir.location = _MAIN_SCRIPT_DIR
|
||||||
|
p.generate(dir, "compile_commands.json", p.modules.ecc.generateFile)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
return function(cfg)
|
||||||
|
return (_ACTION == "ecc")
|
||||||
|
end
|
||||||
122
build/ecc/ecc.lua
Normal file
122
build/ecc/ecc.lua
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
|
||||||
|
-- Include module if it is not embedded
|
||||||
|
if premake.modules.ecc == nil then
|
||||||
|
include ( "_preload.lua" )
|
||||||
|
end
|
||||||
|
|
||||||
|
local p = premake
|
||||||
|
local project = p.project
|
||||||
|
|
||||||
|
p.modules.ecc = {}
|
||||||
|
local m = p.modules.ecc
|
||||||
|
|
||||||
|
m._VERSION = "1.0.1-alpha"
|
||||||
|
|
||||||
|
function m.generateFile()
|
||||||
|
p.push("[")
|
||||||
|
for wks in p.global.eachWorkspace() do
|
||||||
|
for prj in p.workspace.eachproject(wks) do
|
||||||
|
m.onProject(prj)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
p.pop("]")
|
||||||
|
end
|
||||||
|
|
||||||
|
function m.onProject(prj)
|
||||||
|
if project.isc(prj) or project.iscpp(prj) then
|
||||||
|
local cfg = m.getConfig(prj)
|
||||||
|
local args = m.getArguments(prj, cfg)
|
||||||
|
local files = table.shallowcopy(prj._.files)
|
||||||
|
for i,node in ipairs(files) do
|
||||||
|
local output = cfg.objdir .. "/" .. node.objname .. ".o"
|
||||||
|
local obj = path.getrelative(prj.location, output)
|
||||||
|
p.push("{")
|
||||||
|
p.push("\"arguments\": [")
|
||||||
|
m.writeArgs(args, obj, node.relpath)
|
||||||
|
p.pop("],")
|
||||||
|
p.w("\"directory\": \"%s\",", prj.location)
|
||||||
|
p.w("\"file\": \"%s\",", node.abspath)
|
||||||
|
p.w("\"output\": \"%s\"", output)
|
||||||
|
p.pop("},")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function m.writeArgs(args, obj, src)
|
||||||
|
for _,arg in ipairs(args) do
|
||||||
|
-- Defines like the following will break JSON format, quotes need to be escaped
|
||||||
|
-- -DEXPORT_API=__attribute__((visibility("default")))
|
||||||
|
local escaped = arg:gsub("\"", "\\\"")
|
||||||
|
p.w("\"%s\",", escaped)
|
||||||
|
end
|
||||||
|
p.w("\"-c\",")
|
||||||
|
p.w("\"-o\",")
|
||||||
|
p.w("\"%s\",", obj)
|
||||||
|
p.w("\"%s\"", src)
|
||||||
|
end
|
||||||
|
|
||||||
|
function m.getConfig(prj)
|
||||||
|
local ocfg = _OPTIONS.config
|
||||||
|
local cfg = {}
|
||||||
|
if ocfg and prj.configs[ocfg] then
|
||||||
|
cfg = prj.configs[ocfg]
|
||||||
|
else
|
||||||
|
cfg = m.defaultconfig(prj)
|
||||||
|
end
|
||||||
|
return cfg
|
||||||
|
end
|
||||||
|
|
||||||
|
function m.getArguments(prj, cfg)
|
||||||
|
local toolset = m.getToolSet(cfg)
|
||||||
|
local args = {}
|
||||||
|
local tool = iif(project.iscpp(prj), "cxx", "cc")
|
||||||
|
local toolname = iif(cfg.prefix, toolset.gettoolname(cfg, tool), toolset.tools[tool])
|
||||||
|
args = table.join(args, toolname)
|
||||||
|
args = table.join(args, toolset.getcppflags(cfg)) -- Preprocessor
|
||||||
|
args = table.join(args, toolset.getdefines(cfg.defines))
|
||||||
|
args = table.join(args, toolset.getundefines(cfg.undefines))
|
||||||
|
args = table.join(args, toolset.getincludedirs(cfg, cfg.includedirs, cfg.sysincludedirs))
|
||||||
|
if project.iscpp(prj) then
|
||||||
|
args = table.join(args, toolset.getcxxflags(cfg))
|
||||||
|
else
|
||||||
|
args = table.join(args, toolset.getcflags(cfg))
|
||||||
|
end
|
||||||
|
args = table.join(args, cfg.buildoptions)
|
||||||
|
return args
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Copied from gmake2 module
|
||||||
|
-- Return default toolset of given config or system default toolset
|
||||||
|
function m.getToolSet(cfg)
|
||||||
|
local default = iif(cfg.system == p.MACOSX, "clang", "gcc")
|
||||||
|
local toolset = p.tools[_OPTIONS.cc or cfg.toolset or default]
|
||||||
|
if not toolset then
|
||||||
|
error("Invalid toolset '" .. cfg.toolset .. "'")
|
||||||
|
end
|
||||||
|
return toolset
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Copied from gmake2 module
|
||||||
|
function m.defaultconfig(target)
|
||||||
|
-- find the right configuration iterator function for this object
|
||||||
|
local eachconfig = iif(target.project, project.eachconfig, p.workspace.eachconfig)
|
||||||
|
local defaultconfig = nil
|
||||||
|
|
||||||
|
-- find the right default configuration platform, grab first configuration that matches
|
||||||
|
if target.defaultplatform then
|
||||||
|
for cfg in eachconfig(target) do
|
||||||
|
if cfg.platform == target.defaultplatform then
|
||||||
|
defaultconfig = cfg
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- grab the first configuration and write the block
|
||||||
|
if not defaultconfig then
|
||||||
|
local iter = eachconfig(target)
|
||||||
|
defaultconfig = iter()
|
||||||
|
end
|
||||||
|
|
||||||
|
return defaultconfig
|
||||||
|
end
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
-- Export Compile Commands module for clangd support
|
||||||
|
require "ecc/ecc"
|
||||||
|
|
||||||
newoption
|
newoption
|
||||||
{
|
{
|
||||||
trigger = "graphics",
|
trigger = "graphics",
|
||||||
@@ -189,13 +192,15 @@ if (downloadRaylib) then
|
|||||||
{
|
{
|
||||||
["Header Files/*"] = { "../include/**.h", "../include/**.hpp", "../src/**.h", "../src/**.hpp"},
|
["Header Files/*"] = { "../include/**.h", "../include/**.hpp", "../src/**.h", "../src/**.hpp"},
|
||||||
["Source Files/*"] = {"../src/**.c", "src/**.cpp"},
|
["Source Files/*"] = {"../src/**.c", "src/**.cpp"},
|
||||||
["Windows Resource Files/*"] = {"../src/**.rc", "src/**.ico"},
|
["Windows Resource Files/*"] = {"../src/**.rc", "../src/**.ico"},
|
||||||
|
["Game Resource Files/*"] = {"../resources/**"},
|
||||||
}
|
}
|
||||||
|
|
||||||
files {"../src/**.c", "../src/**.cpp", "../src/**.h", "../src/**.hpp", "../include/**.h", "../include/**.hpp"}
|
files {"../src/**.c", "../src/**.cpp", "../src/**.h", "../src/**.hpp", "../include/**.h", "../include/**.hpp"}
|
||||||
|
|
||||||
filter {"system:windows", "action:vs*"}
|
filter {"system:windows", "action:vs*"}
|
||||||
files {"../src/*.rc", "../src/*.ico"}
|
files {"../src/*.rc", "../src/*.ico"}
|
||||||
|
files {"../resources/**"}
|
||||||
|
|
||||||
filter{}
|
filter{}
|
||||||
|
|
||||||
|
|||||||
616
src/main.c
616
src/main.c
@@ -1,23 +1,462 @@
|
|||||||
/*
|
/*
|
||||||
Raylib example file.
|
Shooting arrows - ya know
|
||||||
This is an example main file for a simple raylib project.
|
|
||||||
Use this as a starting point or replace it with your code.
|
|
||||||
|
|
||||||
by Jeffery Myers is marked with CC0 1.0. To view a copy of this license, visit https://creativecommons.org/publicdomain/zero/1.0/
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
|
#include "resource_dir.h"
|
||||||
|
|
||||||
#include "resource_dir.h" // utility header for SearchAndSetResourceDir
|
const float G = 458.0;
|
||||||
|
const float attritionCoefficient = 95.0;
|
||||||
|
const int archerSize = 10;
|
||||||
|
const float archerSpeed = 96.0;
|
||||||
|
const float maxBowTension = 921.0;
|
||||||
|
const float bowTensionSpeed = 12.0;
|
||||||
|
|
||||||
int main ()
|
const float spacing = 16;
|
||||||
|
const float bowTensionIndicatorWidth = 360;
|
||||||
|
const float bowTensionIndicatorHeight = 40;
|
||||||
|
|
||||||
|
const float arrowLength = 20.0f;
|
||||||
|
const int groundHeight = 40;
|
||||||
|
|
||||||
|
#define MAX_BLOOD_PARTICLES 800
|
||||||
|
|
||||||
|
// Utility function to map a value from one range to another
|
||||||
|
float map(float value, float fromLow, float fromHigh, float toLow, float toHigh)
|
||||||
|
{
|
||||||
|
return toLow + (toHigh - toLow) * (value - fromLow) / (fromHigh - fromLow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility function to normalize a Vector2
|
||||||
|
Vector2 normalized(Vector2 v)
|
||||||
|
{
|
||||||
|
float len = sqrtf(v.x * v.x + v.y * v.y);
|
||||||
|
if (len == 0.0f)
|
||||||
|
{
|
||||||
|
Vector2 zero = {0.0f, 0.0f};
|
||||||
|
return zero;
|
||||||
|
}
|
||||||
|
Vector2 n = {v.x / len, v.y / len};
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct Target Target;
|
||||||
|
typedef struct Arrow Arrow;
|
||||||
|
|
||||||
|
struct Arrow
|
||||||
|
{
|
||||||
|
Vector2 position;
|
||||||
|
Vector2 speed;
|
||||||
|
Vector2 acceleration;
|
||||||
|
Vector2 direction;
|
||||||
|
bool stuck;
|
||||||
|
Target *hitTarget;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ArrowNode ArrowNode;
|
||||||
|
|
||||||
|
struct ArrowNode
|
||||||
|
{
|
||||||
|
Arrow *data;
|
||||||
|
ArrowNode *prev;
|
||||||
|
ArrowNode *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bleed pattern: alternating durations of squirt (spawn particles) and pause
|
||||||
|
// {squirt, pause, squirt, pause, squirt, pause, squirt,..., 0} — 0 marks end
|
||||||
|
#define BLEED_PHASES 18
|
||||||
|
const float bleedPattern[BLEED_PHASES] = {0.08f, 0.06f, 0.38f, 0.25f, 0.08f, 2.06f, 0.38f, 0.25f, 0.10f, 1.06f, 0.08f, 0.3f, 2.2f, 0.4f, 1.1f, 0.9f, 0.8f, 0.0f};
|
||||||
|
// even indices = squirt, odd indices = pause, last 0 = done
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Vector2 position;
|
||||||
|
Vector2 velocity;
|
||||||
|
float lifetime;
|
||||||
|
float maxLifetime;
|
||||||
|
bool active;
|
||||||
|
} BloodParticle;
|
||||||
|
|
||||||
|
BloodParticle bloodParticles[MAX_BLOOD_PARTICLES];
|
||||||
|
|
||||||
|
void spawn_blood(Vector2 origin, Vector2 direction, int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_BLOOD_PARTICLES && count > 0; i++)
|
||||||
|
{
|
||||||
|
if (!bloodParticles[i].active)
|
||||||
|
{
|
||||||
|
bloodParticles[i].active = true;
|
||||||
|
bloodParticles[i].position = origin;
|
||||||
|
// base direction is opposite to the arrow's flight
|
||||||
|
float baseAngle = atan2f(-direction.y, -direction.x);
|
||||||
|
// spread within ~90 degrees of the opposite direction
|
||||||
|
float spread = ((float)GetRandomValue(-45, 45)) * DEG2RAD;
|
||||||
|
float angle = baseAngle + spread;
|
||||||
|
float speed = (float)GetRandomValue(0, 320);
|
||||||
|
bloodParticles[i].velocity.x = cosf(angle) * speed;
|
||||||
|
bloodParticles[i].velocity.y = sinf(angle) * speed;
|
||||||
|
bloodParticles[i].maxLifetime = 0.4f + (float)GetRandomValue(10, 475) / 100.0f;
|
||||||
|
bloodParticles[i].lifetime = bloodParticles[i].maxLifetime;
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_blood(float deltaTime)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_BLOOD_PARTICLES; i++)
|
||||||
|
{
|
||||||
|
if (!bloodParticles[i].active)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bloodParticles[i].lifetime -= deltaTime;
|
||||||
|
if (bloodParticles[i].lifetime <= 0)
|
||||||
|
{
|
||||||
|
bloodParticles[i].active = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bloodParticles[i].velocity.y += G * 0.5f * deltaTime;
|
||||||
|
bloodParticles[i].position.x += bloodParticles[i].velocity.x * deltaTime;
|
||||||
|
bloodParticles[i].position.y += bloodParticles[i].velocity.y * deltaTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_blood(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_BLOOD_PARTICLES; i++)
|
||||||
|
{
|
||||||
|
if (!bloodParticles[i].active)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float alpha = bloodParticles[i].lifetime / bloodParticles[i].maxLifetime;
|
||||||
|
unsigned char a = (unsigned char)(alpha * 255);
|
||||||
|
Color c = {200, 0, 0, a};
|
||||||
|
float size = 2.0f + alpha * 2.0f;
|
||||||
|
DrawRectangle(
|
||||||
|
(int)(bloodParticles[i].position.x - size / 2),
|
||||||
|
(int)(bloodParticles[i].position.y - size / 2),
|
||||||
|
(int)size, (int)size, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Target
|
||||||
|
{
|
||||||
|
Vector2 position;
|
||||||
|
Vector2 speed;
|
||||||
|
bool bleeding;
|
||||||
|
bool grounded;
|
||||||
|
int bleedPhase;
|
||||||
|
float bleedTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct TargetNode TargetNode;
|
||||||
|
|
||||||
|
struct TargetNode
|
||||||
|
{
|
||||||
|
Target *data;
|
||||||
|
TargetNode *prev;
|
||||||
|
TargetNode *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
void add_target(TargetNode *head, Vector2 position)
|
||||||
|
{
|
||||||
|
TargetNode *el = head;
|
||||||
|
while (el->next)
|
||||||
|
{
|
||||||
|
el = el->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Target *t = malloc(sizeof(Target));
|
||||||
|
t->position = position;
|
||||||
|
t->speed.x = 0;
|
||||||
|
t->speed.y = 0;
|
||||||
|
t->bleeding = false;
|
||||||
|
t->grounded = false;
|
||||||
|
t->bleedPhase = 0;
|
||||||
|
t->bleedTimer = 0;
|
||||||
|
|
||||||
|
TargetNode *newNode = (TargetNode *)malloc(sizeof(TargetNode));
|
||||||
|
newNode->data = t;
|
||||||
|
newNode->prev = el;
|
||||||
|
newNode->next = NULL;
|
||||||
|
|
||||||
|
el->next = newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_target(TargetNode *node)
|
||||||
|
{
|
||||||
|
node->prev->next = node->next;
|
||||||
|
if (node->next)
|
||||||
|
node->next->prev = node->prev;
|
||||||
|
free(node->data);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fire_arrow(ArrowNode *head, Vector2 origin, Vector2 acceleration)
|
||||||
|
{
|
||||||
|
if (!head)
|
||||||
|
{
|
||||||
|
TraceLog(LOG_ERROR, "Cannot fire arrow: head pointer is NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrowNode *el = head;
|
||||||
|
while (el->next)
|
||||||
|
{
|
||||||
|
el = el->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Arrow *a = malloc(sizeof(Arrow));
|
||||||
|
a->position.x = origin.x;
|
||||||
|
a->position.y = origin.y;
|
||||||
|
a->speed.x = acceleration.x;
|
||||||
|
a->speed.y = acceleration.y;
|
||||||
|
a->acceleration.x = 0;
|
||||||
|
a->acceleration.y = 0;
|
||||||
|
a->direction = normalized(a->speed);
|
||||||
|
a->stuck = false;
|
||||||
|
a->hitTarget = NULL;
|
||||||
|
|
||||||
|
ArrowNode *newNode = (ArrowNode *)malloc(sizeof(ArrowNode));
|
||||||
|
newNode->data = a;
|
||||||
|
newNode->prev = el;
|
||||||
|
newNode->next = NULL;
|
||||||
|
|
||||||
|
el->next = newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_arrows(ArrowNode *head, TargetNode *targets, Texture targetTex, float deltaTime, float attrition)
|
||||||
|
{
|
||||||
|
Rectangle groundRect = {.x = 0, .y = GetScreenHeight() - groundHeight, .width = GetScreenWidth(), .height = groundHeight};
|
||||||
|
|
||||||
|
ArrowNode *el = head->next;
|
||||||
|
while (el != NULL)
|
||||||
|
{
|
||||||
|
Arrow *a = el->data;
|
||||||
|
|
||||||
|
// skip stuck arrows
|
||||||
|
if (a->stuck)
|
||||||
|
{
|
||||||
|
el = el->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
a->speed.x += a->acceleration.x * deltaTime;
|
||||||
|
a->speed.y += a->acceleration.y * deltaTime;
|
||||||
|
|
||||||
|
// apply gravity directly to speed
|
||||||
|
a->speed.y += G * deltaTime;
|
||||||
|
|
||||||
|
a->position.x += a->speed.x * deltaTime;
|
||||||
|
a->position.y += a->speed.y * deltaTime;
|
||||||
|
|
||||||
|
// update flight direction
|
||||||
|
a->direction = normalized(a->speed);
|
||||||
|
|
||||||
|
// to simulate attrition will scale down the acceleration by a constant
|
||||||
|
float decay = powf(attrition, deltaTime);
|
||||||
|
a->acceleration.x *= decay;
|
||||||
|
a->acceleration.y *= decay;
|
||||||
|
|
||||||
|
// check for target collisions
|
||||||
|
TargetNode *tEl = targets->next;
|
||||||
|
while (tEl != NULL)
|
||||||
|
{
|
||||||
|
Target *t = tEl->data;
|
||||||
|
if (t->bleeding)
|
||||||
|
{
|
||||||
|
tEl = tEl->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Rectangle targetRect = {t->position.x, t->position.y, (float)targetTex.width, (float)targetTex.height};
|
||||||
|
if (CheckCollisionPointRec(a->position, targetRect))
|
||||||
|
{
|
||||||
|
t->bleeding = true;
|
||||||
|
t->bleedPhase = 0;
|
||||||
|
t->bleedTimer = bleedPattern[0];
|
||||||
|
|
||||||
|
// penetrate into the target proportionally to hit speed
|
||||||
|
float hitSpeed = sqrtf(a->speed.x * a->speed.x + a->speed.y * a->speed.y);
|
||||||
|
float maxPenetration = arrowLength * 1.1f;
|
||||||
|
float penetration = (hitSpeed / maxBowTension) * maxPenetration;
|
||||||
|
a->position.x += a->direction.x * penetration;
|
||||||
|
a->position.y += a->direction.y * penetration;
|
||||||
|
|
||||||
|
a->acceleration.x = a->acceleration.y = a->speed.x = a->speed.y = 0;
|
||||||
|
a->stuck = true;
|
||||||
|
a->hitTarget = t;
|
||||||
|
TraceLog(LOG_INFO, "Target hit!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tEl = tEl->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a->stuck)
|
||||||
|
{
|
||||||
|
el = el->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for ground collision
|
||||||
|
if (CheckCollisionPointRec(a->position, groundRect))
|
||||||
|
{
|
||||||
|
a->position.y = GetScreenHeight() - groundHeight;
|
||||||
|
a->acceleration.x = a->acceleration.y = a->speed.x = a->speed.y = 0;
|
||||||
|
a->stuck = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if arrow went offscreen, remove it
|
||||||
|
if (
|
||||||
|
(a->position.x > GetScreenWidth() || a->position.x < 0) ||
|
||||||
|
a->position.y > GetScreenHeight())
|
||||||
|
{
|
||||||
|
el->prev->next = el->next;
|
||||||
|
if (el->next)
|
||||||
|
el->next->prev = el->prev;
|
||||||
|
|
||||||
|
ArrowNode *orphan = el;
|
||||||
|
|
||||||
|
el = el->next;
|
||||||
|
free(orphan->data);
|
||||||
|
free(orphan);
|
||||||
|
|
||||||
|
TraceLog(LOG_INFO, "Removing arrow");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
el = el->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_arrow(ArrowNode *node)
|
||||||
|
{
|
||||||
|
node->prev->next = node->next;
|
||||||
|
if (node->next)
|
||||||
|
node->next->prev = node->prev;
|
||||||
|
free(node->data);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_targets(TargetNode *targets, ArrowNode *arrows, Texture targetTex, float deltaTime)
|
||||||
|
{
|
||||||
|
TargetNode *tEl = targets->next;
|
||||||
|
while (tEl != NULL)
|
||||||
|
{
|
||||||
|
Target *t = tEl->data;
|
||||||
|
if (!t->bleeding)
|
||||||
|
{
|
||||||
|
tEl = tEl->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply gravity and move the target while falling
|
||||||
|
if (!t->grounded)
|
||||||
|
{
|
||||||
|
t->speed.y += G * deltaTime;
|
||||||
|
float dx = t->speed.x * deltaTime;
|
||||||
|
float dy = t->speed.y * deltaTime;
|
||||||
|
t->position.x += dx;
|
||||||
|
t->position.y += dy;
|
||||||
|
|
||||||
|
float groundY = GetScreenHeight() - groundHeight - targetTex.height;
|
||||||
|
if (t->position.y >= groundY)
|
||||||
|
{
|
||||||
|
dy -= (t->position.y - groundY);
|
||||||
|
t->position.y = groundY;
|
||||||
|
t->speed.x = 0;
|
||||||
|
t->speed.y = 0;
|
||||||
|
t->grounded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move stuck arrows along with the target
|
||||||
|
ArrowNode *aEl = arrows->next;
|
||||||
|
while (aEl != NULL)
|
||||||
|
{
|
||||||
|
if (aEl->data->hitTarget == t)
|
||||||
|
{
|
||||||
|
aEl->data->position.x += dx;
|
||||||
|
aEl->data->position.y += dy;
|
||||||
|
}
|
||||||
|
aEl = aEl->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t->bleedTimer -= deltaTime;
|
||||||
|
if (t->bleedTimer > 0)
|
||||||
|
{
|
||||||
|
// during squirt phases (even indices), spawn particles
|
||||||
|
if (t->bleedPhase % 2 == 0)
|
||||||
|
{
|
||||||
|
Vector2 center = {
|
||||||
|
t->position.x + targetTex.width / 2.0f,
|
||||||
|
t->position.y + targetTex.height / 2.0f};
|
||||||
|
|
||||||
|
ArrowNode *aEl = arrows->next;
|
||||||
|
while (aEl != NULL)
|
||||||
|
{
|
||||||
|
ArrowNode *aNext = aEl->next;
|
||||||
|
if (aEl->data->hitTarget == t)
|
||||||
|
{
|
||||||
|
spawn_blood(aEl->data->position, aEl->data->direction, MAX_BLOOD_PARTICLES / 2);
|
||||||
|
}
|
||||||
|
aEl = aNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tEl = tEl->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// advance to next phase
|
||||||
|
t->bleedPhase++;
|
||||||
|
if (t->bleedPhase >= BLEED_PHASES || bleedPattern[t->bleedPhase] == 0.0f)
|
||||||
|
{
|
||||||
|
// remove arrows that hit this target
|
||||||
|
ArrowNode *aEl = arrows->next;
|
||||||
|
while (aEl != NULL)
|
||||||
|
{
|
||||||
|
ArrowNode *aNext = aEl->next;
|
||||||
|
if (aEl->data->hitTarget == t)
|
||||||
|
{
|
||||||
|
remove_arrow(aEl);
|
||||||
|
}
|
||||||
|
aEl = aNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// animation done, remove target and spawn a new one
|
||||||
|
TargetNode *dead = tEl;
|
||||||
|
tEl = tEl->next;
|
||||||
|
remove_target(dead);
|
||||||
|
|
||||||
|
Vector2 newPos = {
|
||||||
|
(float)GetRandomValue(0, GetScreenWidth() - targetTex.width),
|
||||||
|
(float)GetRandomValue(0, GetScreenHeight() / 2)};
|
||||||
|
add_target(targets, newPos);
|
||||||
|
|
||||||
|
TraceLog(LOG_INFO, "Target removed after bleeding, new target spawned");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
t->bleedTimer = bleedPattern[t->bleedPhase];
|
||||||
|
tEl = tEl->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
{
|
{
|
||||||
// Tell the window to use vsync and work on high DPI displays
|
// Tell the window to use vsync and work on high DPI displays
|
||||||
SetConfigFlags(FLAG_VSYNC_HINT | FLAG_WINDOW_HIGHDPI);
|
SetConfigFlags(FLAG_VSYNC_HINT | FLAG_WINDOW_HIGHDPI | FLAG_WINDOW_RESIZABLE);
|
||||||
|
|
||||||
// Create the window and OpenGL context
|
// Create the window and OpenGL context
|
||||||
InitWindow(1280, 800, "Hello Raylib");
|
InitWindow(1280, 800, "Archer");
|
||||||
|
|
||||||
// Utility function from resource_dir.h to find the resources folder and set it as the current working directory so we can load from it
|
// Utility function from resource_dir.h to find the resources folder and set it as the current working directory so we can load from it
|
||||||
SearchAndSetResourceDir("resources");
|
SearchAndSetResourceDir("resources");
|
||||||
@@ -25,26 +464,175 @@ int main ()
|
|||||||
// Load a texture from the resources directory
|
// Load a texture from the resources directory
|
||||||
Texture wabbit = LoadTexture("wabbit_alpha.png");
|
Texture wabbit = LoadTexture("wabbit_alpha.png");
|
||||||
|
|
||||||
|
int screenWidth = GetScreenWidth();
|
||||||
|
int screenHeight = GetScreenHeight();
|
||||||
|
|
||||||
|
Vector2 mousePosition = {0, 0};
|
||||||
|
char coords[200];
|
||||||
|
|
||||||
|
bool trajectoryVisible = false;
|
||||||
|
|
||||||
|
Vector2 archerPosition = {screenWidth / 2 - archerSize / 2, screenHeight - groundHeight - archerSize};
|
||||||
|
|
||||||
|
float bowTension = 0.0;
|
||||||
|
|
||||||
|
ArrowNode *head = (ArrowNode *)calloc(1, sizeof(ArrowNode));
|
||||||
|
|
||||||
|
TargetNode *targets = (TargetNode *)calloc(3, sizeof(TargetNode));
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
// spawn targets at a random position in the top region
|
||||||
|
Vector2 targetPos = {
|
||||||
|
(float)GetRandomValue(0, screenWidth - wabbit.width),
|
||||||
|
(float)GetRandomValue(0, screenHeight / 3)};
|
||||||
|
add_target(targets, targetPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dt = 0;
|
||||||
|
|
||||||
// game loop
|
// game loop
|
||||||
while (!WindowShouldClose()) // run the loop until the user presses ESCAPE or presses the Close button on the window
|
while (!WindowShouldClose()) // run the loop until the user presses ESCAPE or presses the Close button on the window
|
||||||
{
|
{
|
||||||
|
dt = GetFrameTime();
|
||||||
|
|
||||||
|
if (IsWindowResized())
|
||||||
|
{
|
||||||
|
screenWidth = GetScreenWidth();
|
||||||
|
screenHeight = GetScreenHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
mousePosition = GetMousePosition();
|
||||||
|
sprintf(coords, "(x=%1.0f, y=%1.0f)", mousePosition.x, mousePosition.y);
|
||||||
|
|
||||||
|
float tensionRate = -3.0;
|
||||||
|
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT))
|
||||||
|
{
|
||||||
|
tensionRate = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bowTension += bowTensionSpeed * tensionRate;
|
||||||
|
if (bowTension < 0)
|
||||||
|
{
|
||||||
|
bowTension = 0;
|
||||||
|
}
|
||||||
|
if (bowTension > maxBowTension)
|
||||||
|
{
|
||||||
|
bowTension = maxBowTension;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pressing the right mouse button releases the bow istantly
|
||||||
|
if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT))
|
||||||
|
{
|
||||||
|
TraceLog(LOG_INFO, "Arrow launched");
|
||||||
|
|
||||||
|
Vector2 dir = {mousePosition.x - archerPosition.x, mousePosition.y - archerPosition.y};
|
||||||
|
Vector2 direction = normalized(dir);
|
||||||
|
Vector2 force = {direction.x * bowTension, direction.y * bowTension};
|
||||||
|
fire_arrow(head, archerPosition, force);
|
||||||
|
bowTension = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsKeyPressed(KEY_T))
|
||||||
|
{
|
||||||
|
trajectoryVisible = !trajectoryVisible;
|
||||||
|
TraceLog(LOG_INFO, "Toggling trajectory indicators");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsKeyDown(KEY_A))
|
||||||
|
{
|
||||||
|
archerPosition.x -= archerSpeed * dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsKeyDown(KEY_D))
|
||||||
|
{
|
||||||
|
archerPosition.x += archerSpeed * dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_arrows(head, targets, wabbit, dt, attritionCoefficient);
|
||||||
|
update_targets(targets, head, wabbit, dt);
|
||||||
|
update_blood(dt);
|
||||||
|
|
||||||
// drawing
|
// drawing
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
|
|
||||||
// Setup the back buffer for drawing (clear color and depth buffers)
|
// Setup the back buffer for drawing (clear color and depth buffers)
|
||||||
ClearBackground(BLACK);
|
ClearBackground(BLACK);
|
||||||
|
|
||||||
// draw some text using the default font
|
// Draw ground
|
||||||
DrawText("Hello Raylib", 200,200,20,WHITE);
|
DrawRectangle(0, screenHeight - groundHeight, screenWidth, groundHeight, BROWN);
|
||||||
|
|
||||||
// draw our texture to the screen
|
// draw targets
|
||||||
DrawTexture(wabbit, 400, 200, WHITE);
|
TargetNode *drawTarget = targets->next;
|
||||||
|
while (drawTarget != NULL)
|
||||||
|
{
|
||||||
|
Target *t = drawTarget->data;
|
||||||
|
DrawTexture(wabbit, (int)t->position.x, (int)t->position.y, WHITE);
|
||||||
|
drawTarget = drawTarget->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw blood particles
|
||||||
|
draw_blood();
|
||||||
|
|
||||||
|
// for now the archer will be a simple square
|
||||||
|
DrawRectangle(archerPosition.x, archerPosition.y, archerSize, archerSize, GREEN);
|
||||||
|
|
||||||
|
// draw arrows
|
||||||
|
ArrowNode *drawEl = head->next;
|
||||||
|
while (drawEl != NULL)
|
||||||
|
{
|
||||||
|
Arrow *a = drawEl->data;
|
||||||
|
Vector2 dir = a->direction;
|
||||||
|
Vector2 tail = {a->position.x - dir.x * arrowLength, a->position.y - dir.y * arrowLength};
|
||||||
|
DrawLineEx(tail, a->position, 2.0f, YELLOW);
|
||||||
|
drawEl = drawEl->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trajectoryVisible)
|
||||||
|
{
|
||||||
|
// aim hints
|
||||||
|
Vector2 startY = {0, mousePosition.y};
|
||||||
|
DrawLineDashed(startY, mousePosition, 4, 8, GRAY);
|
||||||
|
|
||||||
|
Vector2 startX = {mousePosition.x, screenHeight};
|
||||||
|
DrawLineDashed(startX, mousePosition, 4, 8, GRAY);
|
||||||
|
|
||||||
|
Vector2 bowOrigin = {archerPosition.x + archerSize / 2, archerPosition.y + archerSize / 2};
|
||||||
|
DrawLineDashed(bowOrigin, mousePosition, 4, 8, GRAY);
|
||||||
|
|
||||||
|
// targeting coordinates
|
||||||
|
DrawText(coords, screenWidth - bowTensionIndicatorWidth - spacing, bowTensionIndicatorHeight + 2 * spacing, 24, WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tension indicator
|
||||||
|
DrawRectangleLines(screenWidth - bowTensionIndicatorWidth - spacing, spacing, bowTensionIndicatorWidth, bowTensionIndicatorHeight, WHITE);
|
||||||
|
DrawRectangle(screenWidth - bowTensionIndicatorWidth - spacing, spacing, map(bowTension, 0, maxBowTension, 0, bowTensionIndicatorWidth), bowTensionIndicatorHeight, WHITE);
|
||||||
|
|
||||||
// end the frame and get ready for the next one (display frame, poll input, etc...)
|
// end the frame and get ready for the next one (display frame, poll input, etc...)
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
|
// free arrow linked list
|
||||||
|
ArrowNode *el = head;
|
||||||
|
while (el != NULL)
|
||||||
|
{
|
||||||
|
ArrowNode *next = el->next;
|
||||||
|
free(el->data);
|
||||||
|
free(el);
|
||||||
|
el = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// free target linked list
|
||||||
|
TargetNode *tEl = targets;
|
||||||
|
while (tEl != NULL)
|
||||||
|
{
|
||||||
|
TargetNode *next = tEl->next;
|
||||||
|
free(tEl->data);
|
||||||
|
free(tEl);
|
||||||
|
tEl = next;
|
||||||
|
}
|
||||||
|
|
||||||
// unload our texture so it can be cleaned up
|
// unload our texture so it can be cleaned up
|
||||||
UnloadTexture(wabbit);
|
UnloadTexture(wabbit);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user