commit
278edfcb2b
@ -0,0 +1,33 @@ |
|||||||
|
--- |
||||||
|
name: Bug report |
||||||
|
about: Create a report to help us improve |
||||||
|
title: '' |
||||||
|
labels: bug |
||||||
|
assignees: Moros1138 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
**Describe the bug** |
||||||
|
A clear and concise description of what the bug is. |
||||||
|
|
||||||
|
**To Reproduce** |
||||||
|
Steps to reproduce the behavior: |
||||||
|
1. Go to '...' |
||||||
|
2. Click on '....' |
||||||
|
3. Scroll down to '....' |
||||||
|
4. See error |
||||||
|
|
||||||
|
**Expected behavior** |
||||||
|
A clear and concise description of what you expected to happen. |
||||||
|
|
||||||
|
**Screenshots** |
||||||
|
If applicable, add screenshots to help explain your problem. |
||||||
|
|
||||||
|
**Desktop (please complete the following information):** |
||||||
|
- OS: [e.g. Arch, Manjaro, Ubuntu, Windows] |
||||||
|
- Toolchain: [e.g. Clang, GCC, Visual Studio] |
||||||
|
- Toolchain Version: [e.g. gcc 11.2.0] |
||||||
|
- CMake Version: [e.g. 3.10] |
||||||
|
|
||||||
|
**Additional context** |
||||||
|
Add any other context about the problem here. |
@ -0,0 +1,20 @@ |
|||||||
|
--- |
||||||
|
name: Feature request |
||||||
|
about: Suggest an idea for this project |
||||||
|
title: "[Feature Request]" |
||||||
|
labels: enhancement |
||||||
|
assignees: Moros1138 |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.** |
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] |
||||||
|
|
||||||
|
**Describe the solution you'd like** |
||||||
|
A clear and concise description of what you want to happen. |
||||||
|
|
||||||
|
**Describe alternatives you've considered** |
||||||
|
A clear and concise description of any alternative solutions or features you've considered. |
||||||
|
|
||||||
|
**Additional context** |
||||||
|
Add any other context or screenshots about the feature request here. |
@ -0,0 +1,8 @@ |
|||||||
|
build |
||||||
|
linux-build |
||||||
|
emscripten-build |
||||||
|
nmake-build |
||||||
|
mingw-build |
||||||
|
vs-build |
||||||
|
.vscode |
||||||
|
.cache |
@ -0,0 +1,292 @@ |
|||||||
|
# require version 3.10 or higher |
||||||
|
cmake_minimum_required(VERSION 3.10) |
||||||
|
|
||||||
|
# |
||||||
|
# Project |
||||||
|
# |
||||||
|
# - dictates the output executable filename |
||||||
|
# |
||||||
|
project(TestApp) |
||||||
|
|
||||||
|
# Options you can set via command-line |
||||||
|
option(HAS_TERMINAL "Show a terminal window for STDOUT/STDERR" ON) |
||||||
|
|
||||||
|
# |
||||||
|
# C_CXX_SOURCES_DIR |
||||||
|
# |
||||||
|
# - the place where your C/C++ source files are located |
||||||
|
# |
||||||
|
set(C_CXX_SOURCES_DIR "src") |
||||||
|
|
||||||
|
# |
||||||
|
# C_CXX_HEADERS_DIR |
||||||
|
# |
||||||
|
# - the place where your C/C++ header files are located |
||||||
|
# |
||||||
|
set(C_CXX_HEADERS_DIR "include") |
||||||
|
|
||||||
|
# |
||||||
|
# ASSETS_DIR |
||||||
|
# |
||||||
|
# - the place where your pictures, sound files, etc.. live |
||||||
|
# |
||||||
|
set(ASSETS_DIR "assets") |
||||||
|
|
||||||
|
########################################################################## |
||||||
|
# DO NOT EDIT BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING!! # |
||||||
|
########################################################################## |
||||||
|
|
||||||
|
# Set C++ Standards |
||||||
|
set(CMAKE_CXX_STANDARD 20) |
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON) |
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF) |
||||||
|
|
||||||
|
# output executable basename |
||||||
|
set(OutputExecutable "${CMAKE_PROJECT_NAME}") |
||||||
|
|
||||||
|
###################################################################### |
||||||
|
# Directories |
||||||
|
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") |
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") |
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") |
||||||
|
|
||||||
|
# We need to specify the output for each configuration to make it work |
||||||
|
# on Visual Studio solutions. |
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/lib") |
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/lib") |
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin") |
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/lib") |
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/lib") |
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/bin") |
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/lib") |
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/lib") |
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin") |
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_PROFILE "${CMAKE_BINARY_DIR}/lib") |
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_PROFILE "${CMAKE_BINARY_DIR}/lib") |
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_PROFILE "${CMAKE_BINARY_DIR}/bin") |
||||||
|
|
||||||
|
set(SOURCE_DATA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${ASSETS_DIR}) |
||||||
|
set(SOURCE_CXX_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${C_CXX_HEADERS_DIR}) |
||||||
|
set(SOURCE_CXX_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${C_CXX_SOURCES_DIR}) |
||||||
|
|
||||||
|
# Source Files are Curated Here |
||||||
|
file( |
||||||
|
GLOB_RECURSE SOURCE_CXX_FILES |
||||||
|
"${SOURCE_CXX_SRC_DIR}/*.cpp" |
||||||
|
) |
||||||
|
|
||||||
|
# Search in the "cmake" directory for additional CMake modules. |
||||||
|
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) |
||||||
|
|
||||||
|
# Executable aka binary output |
||||||
|
add_executable(${OutputExecutable} ${SOURCE_CXX_FILES}) |
||||||
|
|
||||||
|
###################################################################### |
||||||
|
# MacOS |
||||||
|
###################################################################### |
||||||
|
|
||||||
|
|
||||||
|
if(APPLE) |
||||||
|
|
||||||
|
# OpenGL |
||||||
|
set(OpenGL_GL_PREFERENCE LEGACY) |
||||||
|
find_package(OpenGL REQUIRED) |
||||||
|
include_directories(${OpenGL_INCLUDE_DIRS}) |
||||||
|
target_link_libraries(${OutputExecutable} ${OpenGL_LIBRARIES} OpenGL::GL) |
||||||
|
|
||||||
|
# Carbon |
||||||
|
FIND_LIBRARY(CARBON_LIBRARY Carbon) |
||||||
|
target_link_libraries(${OutputExecutable} ${CARBON_LIBRARY}) |
||||||
|
|
||||||
|
# GLUT |
||||||
|
find_package(GLUT REQUIRED) |
||||||
|
target_link_libraries(${OutputExecutable} ${GLUT_LIBRARIES}) |
||||||
|
|
||||||
|
# Threads |
||||||
|
find_package(Threads REQUIRED) |
||||||
|
target_link_libraries(${OutputExecutable} Threads::Threads) |
||||||
|
include_directories(${Threads_INCLUDE_DIRS}) |
||||||
|
|
||||||
|
find_package(PNG REQUIRED) |
||||||
|
target_link_libraries(${OutputExecutable} PNG::PNG) |
||||||
|
include_directories(${PNG_INCLUDE_DIRS}) |
||||||
|
|
||||||
|
endif() # APPLE |
||||||
|
|
||||||
|
###################################################################### |
||||||
|
# Windows: MinGW |
||||||
|
###################################################################### |
||||||
|
if(WIN32 AND MINGW) |
||||||
|
|
||||||
|
# OpenGL |
||||||
|
set(OpenGL_GL_PREFERENCE LEGACY) |
||||||
|
find_package(OpenGL REQUIRED) |
||||||
|
include_directories(${OpenGL_INCLUDE_DIRS}) |
||||||
|
target_link_libraries(${OutputExecutable} ${OpenGL_LIBRARIES} OpenGL::GL) |
||||||
|
|
||||||
|
if (NOT HAS_TERMINAL) |
||||||
|
target_link_libraries(${OutputExecutable} -mwindows -municode) |
||||||
|
endif (NOT HAS_TERMINAL) |
||||||
|
|
||||||
|
# GDI+ |
||||||
|
set(GDIPLUS_LIBRARY gdiplus) |
||||||
|
target_link_libraries(${OutputExecutable} ${GDIPLUS_LIBRARY}) |
||||||
|
|
||||||
|
# Shlwapi |
||||||
|
set(SHLWAPI_LIBRARY shlwapi) |
||||||
|
target_link_libraries(${OutputExecutable} ${SHLWAPI_LIBRARY}) |
||||||
|
|
||||||
|
# Dwmapi |
||||||
|
set(DWMAPI_LIBRARY dwmapi) |
||||||
|
target_link_libraries(${OutputExecutable} ${DWMAPI_LIBRARY}) |
||||||
|
|
||||||
|
# stdc++fs |
||||||
|
target_link_libraries(${OutputExecutable} stdc++fs) |
||||||
|
|
||||||
|
endif() |
||||||
|
|
||||||
|
###################################################################### |
||||||
|
# Windows: Visual Studio / MSVC |
||||||
|
###################################################################### |
||||||
|
if(WIN32 AND MSVC) |
||||||
|
|
||||||
|
# OpenGL |
||||||
|
set(OpenGL_GL_PREFERENCE LEGACY) |
||||||
|
find_package(OpenGL REQUIRED) |
||||||
|
include_directories(${OpenGL_INCLUDE_DIRS}) |
||||||
|
target_link_libraries(${OutputExecutable} ${OpenGL_LIBRARIES} OpenGL::GL) |
||||||
|
|
||||||
|
# set the startup project to the target executable instead of ALL_BUILD |
||||||
|
set_property( |
||||||
|
DIRECTORY |
||||||
|
${CMAKE_CURRENT_SOURCE_DIR} |
||||||
|
PROPERTY |
||||||
|
VS_STARTUP_PROJECT |
||||||
|
${OutputExecutable} |
||||||
|
) |
||||||
|
|
||||||
|
# set working directory for Visual Studio Debugger |
||||||
|
set_target_properties( |
||||||
|
${OutputExecutable} PROPERTIES |
||||||
|
VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/bin" |
||||||
|
) |
||||||
|
|
||||||
|
# set subsytem, console if HAS_TERMINAL is true. windows if not |
||||||
|
if (HAS_TERMINAL) |
||||||
|
target_link_options(${OutputExecutable} PRIVATE "/SUBSYSTEM:CONSOLE") |
||||||
|
else () |
||||||
|
target_link_options(${OutputExecutable} PRIVATE "/SUBSYSTEM:WINDOWS") |
||||||
|
endif () |
||||||
|
|
||||||
|
# GDI+ |
||||||
|
set(GDIPLUS_LIBRARY gdiplus) |
||||||
|
target_link_libraries(${OutputExecutable} ${GDIPLUS_LIBRARY}) |
||||||
|
|
||||||
|
# Shlwapi |
||||||
|
set(SHLWAPI_LIBRARY shlwapi) |
||||||
|
target_link_libraries(${OutputExecutable} ${SHLWAPI_LIBRARY}) |
||||||
|
|
||||||
|
# Dwmapi |
||||||
|
set(DWMAPI_LIBRARY dwmapi) |
||||||
|
target_link_libraries(${OutputExecutable} ${DWMAPI_LIBRARY}) |
||||||
|
|
||||||
|
endif() # Visual Studio / MSVC |
||||||
|
|
||||||
|
###################################################################### |
||||||
|
# Linux: using anything? |
||||||
|
###################################################################### |
||||||
|
if(UNIX AND NOT APPLE AND NOT EMSCRIPTEN) |
||||||
|
|
||||||
|
# OpenGL |
||||||
|
set(OpenGL_GL_PREFERENCE LEGACY) |
||||||
|
find_package(OpenGL REQUIRED) |
||||||
|
include_directories(${OpenGL_INCLUDE_DIRS}) |
||||||
|
target_link_libraries(${OutputExecutable} ${OpenGL_LIBRARIES} OpenGL::GL) |
||||||
|
|
||||||
|
# X11 |
||||||
|
find_package(X11 REQUIRED) |
||||||
|
target_link_libraries(${OutputExecutable} X11::X11) |
||||||
|
|
||||||
|
include_directories(${X11_INCLUDE_DIRS}) |
||||||
|
|
||||||
|
# Threads |
||||||
|
find_package(Threads REQUIRED) |
||||||
|
target_link_libraries(${OutputExecutable} Threads::Threads) |
||||||
|
include_directories(${Threads_INCLUDE_DIRS}) |
||||||
|
|
||||||
|
find_package(PNG REQUIRED) |
||||||
|
target_link_libraries(${OutputExecutable} PNG::PNG) |
||||||
|
include_directories(${PNG_INCLUDE_DIRS}) |
||||||
|
|
||||||
|
# stdc++fs |
||||||
|
target_link_libraries(${OutputExecutable} stdc++fs) |
||||||
|
|
||||||
|
# dl, for miniaudio |
||||||
|
target_link_libraries(${OutputExecutable} dl) |
||||||
|
|
||||||
|
endif() # Linux |
||||||
|
|
||||||
|
###################################################################### |
||||||
|
# Emscripten |
||||||
|
###################################################################### |
||||||
|
if (EMSCRIPTEN) |
||||||
|
|
||||||
|
# Generate an HTML file |
||||||
|
set(CMAKE_EXECUTABLE_SUFFIX .html) |
||||||
|
|
||||||
|
# Build Cache: SDL2_mixer, libpng, zlib |
||||||
|
execute_process(COMMAND "${EMSCRIPTEN_ROOT_PATH}/embuilder${EMCC_SUFFIX}" build sdl2_mixer libpng zlib) |
||||||
|
|
||||||
|
if(EXISTS "${SOURCE_DATA_DIR}" AND IS_DIRECTORY "${SOURCE_DATA_DIR}") |
||||||
|
target_link_options( |
||||||
|
${OutputExecutable} |
||||||
|
PRIVATE |
||||||
|
-sALLOW_MEMORY_GROWTH=1 |
||||||
|
-sMAX_WEBGL_VERSION=2 |
||||||
|
-sMIN_WEBGL_VERSION=2 |
||||||
|
-sUSE_LIBPNG=1 |
||||||
|
-sLLD_REPORT_UNDEFINED |
||||||
|
--preload-file ${SOURCE_DATA_DIR}@assets) |
||||||
|
else() |
||||||
|
target_link_options( |
||||||
|
${OutputExecutable} |
||||||
|
PRIVATE |
||||||
|
-sALLOW_MEMORY_GROWTH=1 |
||||||
|
-sMAX_WEBGL_VERSION=2 |
||||||
|
-sMIN_WEBGL_VERSION=2 |
||||||
|
-sUSE_LIBPNG=1 |
||||||
|
-sLLD_REPORT_UNDEFINED) |
||||||
|
endif() |
||||||
|
|
||||||
|
endif() # Emscripten |
||||||
|
|
||||||
|
###################################################################### |
||||||
|
# Set include directory |
||||||
|
###################################################################### |
||||||
|
if(IS_DIRECTORY ${SOURCE_CXX_INCLUDE_DIR}) |
||||||
|
include_directories(${SOURCE_CXX_INCLUDE_DIR}) |
||||||
|
endif() |
||||||
|
|
||||||
|
###################################################################### |
||||||
|
# Copy assets/ directory target |
||||||
|
###################################################################### |
||||||
|
|
||||||
|
set(DATA_OUTPUT_DIR ${CMAKE_BINARY_DIR}/bin/${ASSETS_DIR}) |
||||||
|
|
||||||
|
file(GLOB_RECURSE src_data_files |
||||||
|
RELATIVE ${SOURCE_DATA_DIR}/ "${SOURCE_DATA_DIR}/*.*" "${SOURCE_DATA_DIR}/*") |
||||||
|
foreach(fn ${src_data_files}) |
||||||
|
add_custom_command( |
||||||
|
OUTPUT ${DATA_OUTPUT_DIR}/${fn} |
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy ${SOURCE_DATA_DIR}/${fn} ${DATA_OUTPUT_DIR}/${fn} |
||||||
|
MAIN_DEPENDENCY ${SOURCE_DATA_DIR}/${fn}) |
||||||
|
list(APPEND out_data_files ${DATA_OUTPUT_DIR}/${fn}) |
||||||
|
endforeach() |
||||||
|
|
||||||
|
add_custom_target(copy_data DEPENDS ${out_data_files}) |
||||||
|
|
||||||
|
# Copy Asset Files, if not Emscripten |
||||||
|
if (NOT EMSCRIPTEN) |
||||||
|
add_dependencies(${OutputExecutable} copy_data) |
||||||
|
endif() |
@ -0,0 +1,69 @@ |
|||||||
|
The following license applies to the repository, unless otherwised credit. |
||||||
|
|
||||||
|
+---------------------------------------------------------------------------- |
||||||
|
| The Unlicense |
||||||
|
+---------------------------------------------------------------------------- |
||||||
|
|
||||||
|
This is free and unencumbered software released into the public domain. |
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute |
||||||
|
this software, either in source code form or as a compiled binary, for any |
||||||
|
purpose, commercial or non-commercial, and by any means. |
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors of |
||||||
|
this software dedicate any and all copyright interest in the software to |
||||||
|
the public domain. We make this dedication for the benefit of the public |
||||||
|
at large and to the detriment of our heirs and successors. We intend this |
||||||
|
dedication to be an overt act of relinquishment in perpetuity of all present |
||||||
|
and future rights to this software under copyright law. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||||
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||||
|
|
||||||
|
For more information, please refer to the project's repository: |
||||||
|
|
||||||
|
https://github.com/Moros1138/pge-template-project or moros1138@gmail.com |
||||||
|
|
||||||
|
|
||||||
|
+---------------------------------------------------------------------------- |
||||||
|
| External Licenses |
||||||
|
+---------------------------------------------------------------------------- |
||||||
|
The following license applies to usage of the olcPixelGameEngine and olcSoundWaveEngine: |
||||||
|
|
||||||
|
https://github.com/OneLoneCoder/olcPixelGameEngine |
||||||
|
https://github.com/OneLoneCoder/olcSoundWaveEngine |
||||||
|
|
||||||
|
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2018 - 2022 OneLoneCoder.com |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced 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. |
@ -0,0 +1,217 @@ |
|||||||
|
# PGE Template Project v2.25 |
||||||
|
|
||||||
|
This is a template project for use with the [olcPixelGameEngine](https://github.com/OneLoneCoder/olcPixelGameEngine). It serves as a jumping off point for you to build your masterpiece application. |
||||||
|
|
||||||
|
## Features |
||||||
|
|
||||||
|
CMake script for cross-platform building. Tested environments include: |
||||||
|
|
||||||
|
* Linux - with UNIX Makefiles, GNU GCC and LLVM Clang |
||||||
|
* MacOS - with UNIX Makefiles, XCode and LLVM Clang |
||||||
|
* Windows - with Visual Studio, NMake Makefiles, and MinGW Makefiles |
||||||
|
* Emscripten - with UNIX Makefiles, NMake Makefiles, and MinGW Makefiles |
||||||
|
|
||||||
|
# Preparing your Environment |
||||||
|
|
||||||
|
The instructions to prepare your environment have been broken up for convenience. Simply follow the instructions that are pertinent to your situation. |
||||||
|
|
||||||
|
## Linux |
||||||
|
|
||||||
|
### **Requirements** |
||||||
|
|
||||||
|
* C/C++ Toolchain for your Linux distro |
||||||
|
* CMake |
||||||
|
* Git |
||||||
|
* libpng |
||||||
|
* Mesa OpenGL Development Libraries |
||||||
|
|
||||||
|
### **Ubuntu and Ubuntu based distros** |
||||||
|
|
||||||
|
Update your package manager by issuing the following command: |
||||||
|
|
||||||
|
``` |
||||||
|
sudo apt update |
||||||
|
``` |
||||||
|
|
||||||
|
Install toolchain and required software by issuing the following command: |
||||||
|
|
||||||
|
``` |
||||||
|
sudo apt install build-essential cmake git libpng-dev libglu1-mesa-dev |
||||||
|
``` |
||||||
|
|
||||||
|
### **Arch, Manjaro, and Arch based distros** |
||||||
|
|
||||||
|
``` |
||||||
|
sudo pacman -Sy base-devel cmake git libpng mesa |
||||||
|
``` |
||||||
|
|
||||||
|
## MacOS |
||||||
|
|
||||||
|
### **Requirements** |
||||||
|
|
||||||
|
* XCode |
||||||
|
* [Homebrew Package Manager](https://brew.sh/) |
||||||
|
* libpng |
||||||
|
* CMake |
||||||
|
* git |
||||||
|
|
||||||
|
Install XCode from the App Store. |
||||||
|
|
||||||
|
Open the ``Terminal`` App from Finder. go to Applications -> Utilities |
||||||
|
|
||||||
|
Follow the instructions at the [Homebrew Website](https://brew.sh/) to install the Homebrew package manager. |
||||||
|
|
||||||
|
Once Homebrew is installed, issue the following command to install ``cmake``,``libpng``, and ``git``: |
||||||
|
|
||||||
|
|
||||||
|
``` |
||||||
|
brew install libpng |
||||||
|
brew install cmake |
||||||
|
brew install git |
||||||
|
``` |
||||||
|
|
||||||
|
## Windows |
||||||
|
|
||||||
|
### Requirements |
||||||
|
|
||||||
|
* Chocolatey |
||||||
|
* CMake |
||||||
|
* Toolchain (MinGW or Visual Studio / NMake) |
||||||
|
|
||||||
|
The following will be required whether you use MinGW or Visual Studio.You will need to open Powershell, as Administrator. |
||||||
|
|
||||||
|
Visit the [Chocolatey website](https://chocolatey.org/) for instructions on how to install Chocolatey. |
||||||
|
|
||||||
|
Once you've got Chocolatey installed, we can install CMake: |
||||||
|
|
||||||
|
``` |
||||||
|
choco install cmake |
||||||
|
``` |
||||||
|
|
||||||
|
Say ``yes`` to all of the scripts Chocolatey wants you to run! |
||||||
|
|
||||||
|
After the installation has completed, find the Cmake ``bin`` directory, it is typically ``C:\Program Files\CMake\bin`` and add it to your path! |
||||||
|
|
||||||
|
Confirm CMake is installed and in your path by issuing the following command in a Command Prompt: |
||||||
|
|
||||||
|
``` |
||||||
|
cmake --version |
||||||
|
``` |
||||||
|
|
||||||
|
If you recieve an ``command not found`` error double check that you have actually added CMake to your path. |
||||||
|
|
||||||
|
## MinGW |
||||||
|
|
||||||
|
Install MinGW via ``choco install mingw`` from Powershell as Administrator |
||||||
|
|
||||||
|
|
||||||
|
## Visual Studio / NMake |
||||||
|
|
||||||
|
Download and install [Visual Studio: Community Edition](https://visualstudio.microsoft.com/downloads/). |
||||||
|
|
||||||
|
Ensure that you have installed the Desktop C++ option! |
||||||
|
|
||||||
|
# **Usage** |
||||||
|
|
||||||
|
IF YOU HAVE MADE IT HERE AND YOU HAVE NOT SET UP YOUR DEVELOPMENT ENVIRONMENT, GO BACK UP AND READ THE INSTRUCTIONS AGAIN! |
||||||
|
|
||||||
|
## Linux / MacOS (with default toolchains) |
||||||
|
|
||||||
|
Open a Terminal and navigate to the directory which you downloaded the project. Issue the following command: |
||||||
|
|
||||||
|
``` |
||||||
|
cmake . -B linux-build -G "Unix Makefiles" |
||||||
|
``` |
||||||
|
|
||||||
|
CMake will generate UNIX Makefiles you can use to build the project, like so: |
||||||
|
|
||||||
|
``` |
||||||
|
cmake --build linux-build |
||||||
|
``` |
||||||
|
|
||||||
|
The compiled binary will be located in ``linux-build/bin`` directory. |
||||||
|
|
||||||
|
**NOTE: if you're executing the program, ensure you have the correct working directory, which contains the executable!** |
||||||
|
|
||||||
|
## MacOS (with XCode) |
||||||
|
|
||||||
|
Open a Terminal and navigate to the directory which you downloaded the project. Issue the following command: |
||||||
|
|
||||||
|
``` |
||||||
|
cmake . -B xcode-build -G "xcode" |
||||||
|
``` |
||||||
|
|
||||||
|
CMake will generate an XCode project in ``xcode-build``. You can use it like any other XCode project. |
||||||
|
|
||||||
|
## Linux / MacOS (Emscripten) |
||||||
|
|
||||||
|
**These instructions assume you have Emscripten installed, activated, and have the environment set up for an active Terminal.** |
||||||
|
|
||||||
|
Open a Terminal and navigate to the directory which you downloaded the project. Issue the following command: |
||||||
|
|
||||||
|
``` |
||||||
|
emcmake cmake . -B emscripten-build |
||||||
|
``` |
||||||
|
|
||||||
|
Emscripten's ``emcmake`` utility will invoke CMake with all the magic required to make it work with Emscripten. Generating UNIX Makefiles you can use to build the project, like so: |
||||||
|
|
||||||
|
``` |
||||||
|
cmake --build emscripten-build |
||||||
|
``` |
||||||
|
|
||||||
|
The compiled HTML, Javascript, WebAssembly, and Data will be in the ``emscripten-build/bin`` directory. |
||||||
|
|
||||||
|
If you lack some sort of live server extension to your IDE, you can view it using the ``emrun`` utility, like so: |
||||||
|
|
||||||
|
``` |
||||||
|
emrun path/to/build/bin/PROJECTNAME.html |
||||||
|
``` |
||||||
|
|
||||||
|
This command should launch the project in your default web browser. |
||||||
|
|
||||||
|
## Windows (MinGW) |
||||||
|
|
||||||
|
Open the ``Command Prompt`` prompt and navigate to the directory which you downloaded the project. Issue the following command: |
||||||
|
|
||||||
|
``` |
||||||
|
cmake . -B mingw-build -G "MinGW Makefiles" |
||||||
|
``` |
||||||
|
|
||||||
|
CMake will generate MinGW Makefiles you can use to build the project, like so: |
||||||
|
|
||||||
|
``` |
||||||
|
cmake --build mingw-build |
||||||
|
``` |
||||||
|
|
||||||
|
The compiled binary will be located in the ``mingw-build/bin`` directory. |
||||||
|
|
||||||
|
**NOTE: if you're executing the program, ensure you have the correct working directory, which contains the executable!** |
||||||
|
|
||||||
|
## Windows (NMake) |
||||||
|
|
||||||
|
Open the ``x64 Native Tools Command Prompt for VS 2022`` prompt and navigate to the directory which you downloaded the project. Issue the following command: |
||||||
|
|
||||||
|
``` |
||||||
|
cmake . -B nmake-build -G "NMake Makefiles" |
||||||
|
``` |
||||||
|
|
||||||
|
CMake will generate NMake Makefiles you can use to build the project, like so: |
||||||
|
|
||||||
|
``` |
||||||
|
cmake --build nmake-build |
||||||
|
``` |
||||||
|
|
||||||
|
The compiled binary will be located in ``nmake-build/bin`` directory. |
||||||
|
|
||||||
|
**NOTE: if you're executing the program, ensure you have the correct working directory, which contains the executable!** |
||||||
|
|
||||||
|
## Windows (Visual Studio) |
||||||
|
|
||||||
|
Open the ``Command Prompt`` prompt and navigate to the directory which you downloaded the project. Issue the following command: |
||||||
|
|
||||||
|
``` |
||||||
|
cmake . -B vs-build |
||||||
|
``` |
||||||
|
|
||||||
|
CMake will generate a Visual Studio solution and project in ``vs-build``. You can use it like any other Visual Studio Project. |
||||||
|
|
After Width: | Height: | Size: 45 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,477 @@ |
|||||||
|
#pragma once |
||||||
|
/*
|
||||||
|
olcPGEX_MiniAudio.h |
||||||
|
|
||||||
|
+-------------------------------------------------------------+ |
||||||
|
| OneLoneCoder Pixel Game Engine Extension | |
||||||
|
| MiniAudio v1.5 | |
||||||
|
+-------------------------------------------------------------+ |
||||||
|
|
||||||
|
NOTE: UNDER ACTIVE DEVELOPMENT - THERE MAY BE BUGS/GLITCHES |
||||||
|
|
||||||
|
What is this? |
||||||
|
~~~~~~~~~~~~~ |
||||||
|
This extension abstracts the very robust and powerful miniaudio |
||||||
|
library. It provides simple loading and playback of WAV and MP3 |
||||||
|
files. Because it's built on top of miniaudio, it requires next |
||||||
|
to no addictional build configurations in order to be built |
||||||
|
for cross-platform. |
||||||
|
|
||||||
|
License (OLC-3) |
||||||
|
~~~~~~~~~~~~~~~ |
||||||
|
|
||||||
|
Copyright 2023 Moros Smith <moros1138@gmail.com> |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, |
||||||
|
are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
1. Redistributions or derivations of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
|
||||||
|
2. Redistributions or derivative works in binary form must reproduce the above |
||||||
|
copyright notice. This list of conditions and the following disclaimer must be |
||||||
|
reproduced 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. |
||||||
|
|
||||||
|
Links |
||||||
|
~~~~~ |
||||||
|
YouTube: https://www.youtube.com/@Moros1138
|
||||||
|
GitHub: https://www.github.com/Moros1138
|
||||||
|
Homepage: https://www.moros1138.com
|
||||||
|
*/ |
||||||
|
|
||||||
|
#include "olcPixelGameEngine.h" |
||||||
|
#include <exception> |
||||||
|
|
||||||
|
#ifdef OLC_PGEX_MINIAUDIO |
||||||
|
#define MINIAUDIO_IMPLEMENTATION |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "miniaudio.h" |
||||||
|
|
||||||
|
namespace olc |
||||||
|
{ |
||||||
|
class MiniAudio : public olc::PGEX |
||||||
|
{ |
||||||
|
public: |
||||||
|
std::string name = "olcPGEX_MiniAudio v1.5"; |
||||||
|
|
||||||
|
public: |
||||||
|
MiniAudio(); |
||||||
|
~MiniAudio(); |
||||||
|
virtual bool OnBeforeUserUpdate(float& fElapsedTime) override; |
||||||
|
static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); |
||||||
|
static bool backgroundPlay; |
||||||
|
|
||||||
|
public: // CONFIGURATION
|
||||||
|
// set whether audio will continue playing when the app has lost focus
|
||||||
|
void SetBackgroundPlay(bool state); |
||||||
|
|
||||||
|
public: // LOADING ROUTINES
|
||||||
|
const int LoadSound(const std::string& path); |
||||||
|
void UnloadSound(const int id); |
||||||
|
|
||||||
|
public: // PLAYBACK CONTROLS
|
||||||
|
// plays a sample, can be set to loop
|
||||||
|
void Play(const int id, const bool loop = false); |
||||||
|
// plays a sound file, as a one off, and automatically unloads it
|
||||||
|
void Play(const std::string& path); |
||||||
|
// stops a sample, rewinds to beginning
|
||||||
|
void Stop(const int id); |
||||||
|
// pauses a sample, does not change position
|
||||||
|
void Pause(const int id); |
||||||
|
// toggle between play and pause
|
||||||
|
void Toggle(const int id, bool rewind = false); |
||||||
|
|
||||||
|
public: // SEEKING CONTROLS
|
||||||
|
// seek to the provided position in the sound, by milliseconds
|
||||||
|
void Seek(const int id, const unsigned long long milliseconds); |
||||||
|
// seek to the provided position in the sound, by float 0.f is beginning, 1.0f is end
|
||||||
|
void Seek(const int id, const float& location); |
||||||
|
// seek forward from current position by the provided time
|
||||||
|
void Forward(const int id, const unsigned long long milliseconds); |
||||||
|
// seek forward from current position by the provided time
|
||||||
|
void Rewind(const int id, const unsigned long long milliseconds); |
||||||
|
|
||||||
|
public: // MISC CONTROLS
|
||||||
|
// set volume of a sound, 0.0f is mute, 1.0f is full
|
||||||
|
void SetVolume(const int id, const float& volume); |
||||||
|
// set pan of a sound, -1.0f is left, 1.0f is right, 0.0f is center
|
||||||
|
void SetPan(const int id, const float& pan); |
||||||
|
// set pitch of a sound, 1.0f is normal
|
||||||
|
void SetPitch(const int id, const float& pitch); |
||||||
|
|
||||||
|
public: // MISC INFORMATION
|
||||||
|
// determine if a sound is playing
|
||||||
|
bool IsPlaying(const int id); |
||||||
|
// gets the current position in the sound, in milliseconds
|
||||||
|
unsigned long long GetCursorMilliseconds(const int id); |
||||||
|
// gets the current position in the sound, as a float between 0.0f and 1.0f
|
||||||
|
float GetCursorFloat(const int id); |
||||||
|
|
||||||
|
public: // ADVANCED FEATURES for those who want to use more of miniaudio
|
||||||
|
// gets the currently loaded persistent sounds
|
||||||
|
const std::vector<ma_sound*>& GetSounds() const; |
||||||
|
// gets the currently loaded one-off sounds
|
||||||
|
const std::vector<ma_sound*>& GetOneOffSounds() const; |
||||||
|
// gets a pointer to the ma_device
|
||||||
|
ma_device* GetDevice(); |
||||||
|
// gets a pointer to the ma_engine
|
||||||
|
ma_engine* GetEngine(); |
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/*
|
||||||
|
Soooo, i'm not going to spend a whole lot of time |
||||||
|
documenting miniaudio features, if you want to |
||||||
|
know more I invite you to visit their very very |
||||||
|
nicely documented webiste at: |
||||||
|
|
||||||
|
https://miniaud.io/docs/manual/index.html
|
||||||
|
*/ |
||||||
|
|
||||||
|
ma_device device; |
||||||
|
ma_engine engine; |
||||||
|
ma_resource_manager resourceManager; |
||||||
|
|
||||||
|
// sample rate for the device and engine
|
||||||
|
int sampleRate; |
||||||
|
// this is where the sounds are kept
|
||||||
|
std::vector<ma_sound*> vecSounds; |
||||||
|
std::vector<ma_sound*> vecOneOffSounds; |
||||||
|
}; |
||||||
|
|
||||||
|
/**
|
||||||
|
* EXCEPTIONS, long story short. I needed to be able |
||||||
|
* to construct the PGEX in a state where it could |
||||||
|
* fail at runtime. If you have a better way of |
||||||
|
* accomplishing the PGEX pattern without using |
||||||
|
* exceptions, I'm open to suggestions! |
||||||
|
*/ |
||||||
|
struct MiniAudioDeviceException : public std::exception |
||||||
|
{ |
||||||
|
const char* what() const throw() |
||||||
|
{ |
||||||
|
return "Failed to initialize a device."; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
struct MiniAudioResourceManagerException : public std::exception |
||||||
|
{ |
||||||
|
const char* what() const throw() |
||||||
|
{ |
||||||
|
return "Failed to initialize the resource manager."; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
struct MiniAudioEngineException : public std::exception |
||||||
|
{ |
||||||
|
const char* what() const throw() |
||||||
|
{ |
||||||
|
return "Failed to initialize the audio engine."; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
struct MiniAudioSoundException : public std::exception |
||||||
|
{ |
||||||
|
const char* what() const throw() |
||||||
|
{ |
||||||
|
return "Failed to initialize a sound."; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#ifdef OLC_PGEX_MINIAUDIO |
||||||
|
#undef OLC_PGEX_MINIAUDIO |
||||||
|
|
||||||
|
namespace olc |
||||||
|
{ |
||||||
|
bool MiniAudio::backgroundPlay = false; |
||||||
|
|
||||||
|
MiniAudio::MiniAudio() : olc::PGEX(true) |
||||||
|
{ |
||||||
|
sampleRate = 48000; |
||||||
|
|
||||||
|
ma_device_config deviceConfig = ma_device_config_init(ma_device_type_playback); |
||||||
|
deviceConfig.playback.format = ma_format_f32; |
||||||
|
deviceConfig.playback.channels = 2; |
||||||
|
deviceConfig.sampleRate = sampleRate; |
||||||
|
deviceConfig.dataCallback = MiniAudio::data_callback; |
||||||
|
deviceConfig.pUserData = &engine; |
||||||
|
|
||||||
|
if(ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) |
||||||
|
throw MiniAudioDeviceException(); |
||||||
|
|
||||||
|
ma_resource_manager_config resourceManagerConfig = ma_resource_manager_config_init(); |
||||||
|
resourceManagerConfig.decodedFormat = ma_format_f32; |
||||||
|
resourceManagerConfig.decodedChannels = 0; |
||||||
|
resourceManagerConfig.decodedSampleRate = sampleRate; |
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__ |
||||||
|
resourceManagerConfig.jobThreadCount = 0;
|
||||||
|
resourceManagerConfig.flags |= MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING; |
||||||
|
resourceManagerConfig.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING; |
||||||
|
#endif |
||||||
|
|
||||||
|
if(ma_resource_manager_init(&resourceManagerConfig, &resourceManager) != MA_SUCCESS) |
||||||
|
throw MiniAudioResourceManagerException(); |
||||||
|
|
||||||
|
ma_engine_config engineConfig = ma_engine_config_init(); |
||||||
|
engineConfig.pDevice = &device; |
||||||
|
engineConfig.pResourceManager = &resourceManager;
|
||||||
|
|
||||||
|
if(ma_engine_init(&engineConfig, &engine) != MA_SUCCESS) |
||||||
|
throw MiniAudioEngineException(); |
||||||
|
|
||||||
|
MiniAudio::backgroundPlay = false;
|
||||||
|
} |
||||||
|
|
||||||
|
MiniAudio::~MiniAudio() |
||||||
|
{ |
||||||
|
for(auto sound : vecSounds) |
||||||
|
{ |
||||||
|
if(sound != nullptr) |
||||||
|
{ |
||||||
|
ma_sound_uninit(sound); |
||||||
|
delete sound; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ma_resource_manager_uninit(&resourceManager); |
||||||
|
|
||||||
|
ma_engine_uninit(&engine);
|
||||||
|
} |
||||||
|
|
||||||
|
bool MiniAudio::OnBeforeUserUpdate(float& fElapsedTime) |
||||||
|
{ |
||||||
|
#ifdef __EMSCRIPTEN__ |
||||||
|
ma_resource_manager_process_next_job(&resourceManager); |
||||||
|
#endif |
||||||
|
|
||||||
|
for(int i = 0; i < vecOneOffSounds.size(); i++) |
||||||
|
{ |
||||||
|
if(!ma_sound_is_playing(vecOneOffSounds.at(i))) |
||||||
|
{ |
||||||
|
ma_sound_uninit(vecOneOffSounds.at(i)); |
||||||
|
vecOneOffSounds.erase(vecOneOffSounds.begin() + i); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) |
||||||
|
{ |
||||||
|
if(!MiniAudio::backgroundPlay && !pge->IsFocused()) |
||||||
|
return; |
||||||
|
|
||||||
|
ma_engine_read_pcm_frames((ma_engine*)(pDevice->pUserData), pOutput, frameCount, NULL); |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::SetBackgroundPlay(bool state) |
||||||
|
{ |
||||||
|
MiniAudio::backgroundPlay = state; |
||||||
|
} |
||||||
|
|
||||||
|
const int MiniAudio::LoadSound(const std::string& path) |
||||||
|
{ |
||||||
|
// create the sound
|
||||||
|
ma_sound* sound = new ma_sound(); |
||||||
|
|
||||||
|
// load it from the file and decode it
|
||||||
|
if(ma_sound_init_from_file(&engine, path.c_str(), MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, NULL, NULL, sound) != MA_SUCCESS) |
||||||
|
throw MiniAudioSoundException(); |
||||||
|
|
||||||
|
// attempt to re-use an empty slot
|
||||||
|
for(int i = 0; i < vecSounds.size(); i++) |
||||||
|
{ |
||||||
|
if(vecSounds.at(i) == nullptr) |
||||||
|
{ |
||||||
|
vecSounds.at(i) = sound; |
||||||
|
return i; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// no empty slots, make more room!
|
||||||
|
const int id = vecSounds.size(); |
||||||
|
vecSounds.push_back(sound); |
||||||
|
|
||||||
|
return id; |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::UnloadSound(const int id) |
||||||
|
{ |
||||||
|
ma_sound_uninit(vecSounds.at(id)); |
||||||
|
delete vecSounds.at(id); |
||||||
|
vecSounds.at(id) = nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::Play(const int id, const bool loop) |
||||||
|
{ |
||||||
|
if(ma_sound_is_playing(vecSounds.at(id))) |
||||||
|
{ |
||||||
|
ma_sound_seek_to_pcm_frame(vecSounds.at(id), 0); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
ma_sound_set_looping(vecSounds.at(id), loop); |
||||||
|
ma_sound_start(vecSounds.at(id)); |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::Play(const std::string& path) |
||||||
|
{ |
||||||
|
// create the sound
|
||||||
|
ma_sound* sound = new ma_sound(); |
||||||
|
|
||||||
|
// load it from the file and decode it
|
||||||
|
if(ma_sound_init_from_file(&engine, path.c_str(), MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_ASYNC, NULL, NULL, sound) != MA_SUCCESS) |
||||||
|
throw MiniAudioSoundException(); |
||||||
|
|
||||||
|
ma_sound_start(sound); |
||||||
|
vecOneOffSounds.push_back(sound); |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::Stop(const int id) |
||||||
|
{ |
||||||
|
ma_sound_seek_to_pcm_frame(vecSounds.at(id), 0); |
||||||
|
ma_sound_stop(vecSounds.at(id)); |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::Pause(const int id) |
||||||
|
{ |
||||||
|
auto it = vecSounds.begin() + id; |
||||||
|
ma_sound_stop(vecSounds.at(id)); |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::Toggle(const int id, bool rewind) |
||||||
|
{ |
||||||
|
if(ma_sound_is_playing(vecSounds.at(id))) |
||||||
|
{ |
||||||
|
ma_sound_stop(vecSounds.at(id)); |
||||||
|
|
||||||
|
if(rewind) |
||||||
|
ma_sound_seek_to_pcm_frame(vecSounds.at(id), 0); |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
ma_sound_start(vecSounds.at(id)); |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::Seek(const int id, const unsigned long long milliseconds) |
||||||
|
{ |
||||||
|
unsigned long long frame = (milliseconds * engine.sampleRate) / 1000; |
||||||
|
|
||||||
|
ma_sound_seek_to_pcm_frame(vecSounds.at(id), frame); |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::Seek(const int id, const float& location) |
||||||
|
{ |
||||||
|
unsigned long long length; |
||||||
|
ma_sound_get_length_in_pcm_frames(vecSounds.at(id), &length); |
||||||
|
|
||||||
|
unsigned long long frame = length * location; |
||||||
|
|
||||||
|
ma_sound_seek_to_pcm_frame(vecSounds.at(id), frame); |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::Forward(const int id, const unsigned long long milliseconds) |
||||||
|
{ |
||||||
|
unsigned long long cursor; |
||||||
|
ma_sound_get_cursor_in_pcm_frames(vecSounds.at(id), &cursor); |
||||||
|
|
||||||
|
unsigned long long frame = (milliseconds * engine.sampleRate) / 1000; |
||||||
|
ma_sound_seek_to_pcm_frame(vecSounds.at(id), cursor + frame); |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::Rewind(const int id, const unsigned long long milliseconds) |
||||||
|
{ |
||||||
|
unsigned long long cursor; |
||||||
|
ma_sound_get_cursor_in_pcm_frames(vecSounds.at(id), &cursor); |
||||||
|
|
||||||
|
unsigned long long frame = (milliseconds * engine.sampleRate) / 1000; |
||||||
|
ma_sound_seek_to_pcm_frame(vecSounds.at(id), cursor - frame); |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::SetVolume(const int id, const float& volume) |
||||||
|
{ |
||||||
|
ma_sound_set_volume(vecSounds.at(id), volume); |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::SetPan(const int id, const float& pan) |
||||||
|
{ |
||||||
|
ma_sound_set_pan(vecSounds.at(id), pan); |
||||||
|
} |
||||||
|
|
||||||
|
void MiniAudio::SetPitch(const int id, const float& pitch) |
||||||
|
{ |
||||||
|
ma_sound_set_pitch(vecSounds.at(id), pitch); |
||||||
|
} |
||||||
|
|
||||||
|
unsigned long long MiniAudio::GetCursorMilliseconds(const int id) |
||||||
|
{ |
||||||
|
unsigned long long cursor; |
||||||
|
ma_sound_get_cursor_in_pcm_frames(vecSounds.at(id), &cursor); |
||||||
|
|
||||||
|
cursor /= sampleRate; |
||||||
|
cursor /= 1000; |
||||||
|
|
||||||
|
return cursor; |
||||||
|
} |
||||||
|
|
||||||
|
bool MiniAudio::IsPlaying(const int id) |
||||||
|
{ |
||||||
|
return ma_sound_is_playing(vecSounds.at(id)); |
||||||
|
} |
||||||
|
|
||||||
|
float MiniAudio::GetCursorFloat(const int id) |
||||||
|
{ |
||||||
|
unsigned long long cursor; |
||||||
|
ma_sound_get_cursor_in_pcm_frames(vecSounds.at(id), &cursor); |
||||||
|
|
||||||
|
unsigned long long length; |
||||||
|
ma_sound_get_length_in_pcm_frames(vecSounds.at(id), &length); |
||||||
|
|
||||||
|
return (float)cursor / length; |
||||||
|
} |
||||||
|
|
||||||
|
const std::vector<ma_sound*>& MiniAudio::GetSounds() const |
||||||
|
{ |
||||||
|
return vecSounds; |
||||||
|
} |
||||||
|
|
||||||
|
const std::vector<ma_sound*>& MiniAudio::GetOneOffSounds() const |
||||||
|
{ |
||||||
|
return vecOneOffSounds; |
||||||
|
} |
||||||
|
|
||||||
|
ma_device* MiniAudio::GetDevice() |
||||||
|
{ |
||||||
|
return &device; |
||||||
|
} |
||||||
|
|
||||||
|
ma_engine* MiniAudio::GetEngine() |
||||||
|
{ |
||||||
|
return &engine; |
||||||
|
} |
||||||
|
|
||||||
|
} // olc
|
||||||
|
|
||||||
|
#endif |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,364 @@ |
|||||||
|
#include "olcPixelGameEngine.h" |
||||||
|
#include "olcPGEX_MiniAudio.h" |
||||||
|
|
||||||
|
|
||||||
|
class OneLoneCoder_Asteroids : public olc::PixelGameEngine |
||||||
|
{ |
||||||
|
public: |
||||||
|
OneLoneCoder_Asteroids() |
||||||
|
{ |
||||||
|
sAppName = "Asteroids"; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
struct sSpaceObject |
||||||
|
{ |
||||||
|
int nSize; |
||||||
|
float x; |
||||||
|
float y; |
||||||
|
float dx; |
||||||
|
float dy; |
||||||
|
float angle; |
||||||
|
}; |
||||||
|
|
||||||
|
std::vector<sSpaceObject> vecAsteroids; |
||||||
|
std::vector<sSpaceObject> vecBullets; |
||||||
|
sSpaceObject player; |
||||||
|
bool bDead = false; |
||||||
|
int nScore = 0; |
||||||
|
|
||||||
|
std::vector<std::pair<float, float>> vecModelShip; |
||||||
|
std::vector<std::pair<float, float>> vecModelAsteroid; |
||||||
|
|
||||||
|
std::map<std::string, olc::Renderable*> gfx; |
||||||
|
std::map<std::string, int> sfx; |
||||||
|
|
||||||
|
olc::MiniAudio audio; |
||||||
|
|
||||||
|
public: |
||||||
|
|
||||||
|
bool OnUserCreate() override |
||||||
|
{ |
||||||
|
auto loadGraphic = [&](const std::string& key, const std::string& filepath) |
||||||
|
{ |
||||||
|
olc::Renderable* renderable = new olc::Renderable(); |
||||||
|
renderable->Load(filepath); |
||||||
|
gfx[key] = renderable; |
||||||
|
}; |
||||||
|
|
||||||
|
auto loadSound = [&](const std::string& key, const std::string& filepath) |
||||||
|
{ |
||||||
|
sfx[key] = audio.LoadSound(filepath); |
||||||
|
}; |
||||||
|
|
||||||
|
loadGraphic("background", "assets/gfx/space.png"); |
||||||
|
|
||||||
|
loadSound("bg-music", "assets/sounds/bg-music.wav"); |
||||||
|
loadSound("laser", "assets/sounds/Laser_Shoot11.wav"); |
||||||
|
loadSound("explosion", "assets/sounds/Explosions1.wav"); |
||||||
|
loadSound("lose", "assets/sounds/lose9.wav"); |
||||||
|
loadSound("thruster", "assets/sounds/thruster.wav"); |
||||||
|
|
||||||
|
vecModelShip =
|
||||||
|
{ |
||||||
|
{ 0.0f, -5.0f}, |
||||||
|
{-2.5f, +2.5f}, |
||||||
|
{+2.5f, +2.5f} |
||||||
|
}; // A simple Isoceles Triangle
|
||||||
|
|
||||||
|
// Create a "jagged" circle for the asteroid. It's important it remains
|
||||||
|
// mostly circular, as we do a simple collision check against a perfect
|
||||||
|
// circle.
|
||||||
|
int verts = 20; |
||||||
|
for (int i = 0; i < verts; i++) |
||||||
|
{ |
||||||
|
float noise = (float)rand() / (float)RAND_MAX * 0.4f + 0.8f; |
||||||
|
vecModelAsteroid.push_back(std::make_pair(noise * sinf(((float)i / (float)verts) * 6.28318f),
|
||||||
|
noise * cosf(((float)i / (float)verts) * 6.28318f))); |
||||||
|
} |
||||||
|
|
||||||
|
backgroundLayer = CreateLayer(); |
||||||
|
EnableLayer(backgroundLayer, true); |
||||||
|
|
||||||
|
SetDrawTarget(backgroundLayer); |
||||||
|
DrawSprite(0,0, gfx.at("background")->Sprite()); |
||||||
|
SetDrawTarget(nullptr); |
||||||
|
|
||||||
|
ResetGame(); |
||||||
|
audio.Play(sfx.at("bg-music"), true); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool OnUserDestroy() override |
||||||
|
{ |
||||||
|
for(auto it = gfx.begin(); it != gfx.end(); ++it) |
||||||
|
{ |
||||||
|
delete it->second; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int backgroundLayer = -1; |
||||||
|
|
||||||
|
void ResetGame() |
||||||
|
{ |
||||||
|
// Initialise Player Position
|
||||||
|
player.x = ScreenWidth() / 2.0f; |
||||||
|
player.y = ScreenHeight() / 2.0f; |
||||||
|
player.dx = 0.0f; |
||||||
|
player.dy = 0.0f; |
||||||
|
player.angle = 0.0f; |
||||||
|
|
||||||
|
vecBullets.clear(); |
||||||
|
vecAsteroids.clear(); |
||||||
|
|
||||||
|
// Put in two asteroids
|
||||||
|
vecAsteroids.push_back({ (int)16, player.x - 80.0f, player.y, 10.0f, 40.0f, 0.0f }); |
||||||
|
vecAsteroids.push_back({ (int)16, player.x + 80.0f, player.y, -10.0f, -40.0f, 0.0f }); |
||||||
|
|
||||||
|
// Reset game
|
||||||
|
bDead = false; |
||||||
|
nScore = false; |
||||||
|
} |
||||||
|
|
||||||
|
// Implements "wrap around" for various in-game sytems
|
||||||
|
void WrapCoordinates(float ix, float iy, float &ox, float &oy) |
||||||
|
{ |
||||||
|
ox = ix; |
||||||
|
oy = iy; |
||||||
|
if (ix < 0.0f) ox = ix + (float)ScreenWidth(); |
||||||
|
if (ix >= (float)ScreenWidth()) ox = ix - (float)ScreenWidth(); |
||||||
|
if (iy < 0.0f) oy = iy + (float)ScreenHeight(); |
||||||
|
if (iy >= (float)ScreenHeight()) oy = iy - (float)ScreenHeight(); |
||||||
|
} |
||||||
|
|
||||||
|
// Overriden to handle toroidal drawing routines
|
||||||
|
bool Draw(int x, int y, olc::Pixel col = olc::WHITE) override |
||||||
|
{ |
||||||
|
float fx, fy; |
||||||
|
WrapCoordinates(x, y, fx, fy);
|
||||||
|
return olc::PixelGameEngine::Draw(fx, fy, col); |
||||||
|
} |
||||||
|
|
||||||
|
bool IsPointInsideCircle(float cx, float cy, float radius, float x, float y) |
||||||
|
{ |
||||||
|
return sqrt((x-cx)*(x-cx) + (y-cy)*(y-cy)) < radius; |
||||||
|
} |
||||||
|
|
||||||
|
// Called by olcConsoleGameEngine
|
||||||
|
bool OnUserUpdate(float fElapsedTime) override |
||||||
|
{ |
||||||
|
if (bDead) |
||||||
|
ResetGame(); |
||||||
|
|
||||||
|
// Clear Screen
|
||||||
|
Clear(olc::BLANK); |
||||||
|
|
||||||
|
// Steer Ship
|
||||||
|
if (GetKey(olc::LEFT).bHeld) |
||||||
|
player.angle -= 5.0f * fElapsedTime; |
||||||
|
if (GetKey(olc::RIGHT).bHeld) |
||||||
|
player.angle += 5.0f * fElapsedTime; |
||||||
|
|
||||||
|
// Thrust? Apply ACCELERATION
|
||||||
|
if (GetKey(olc::UP).bHeld) |
||||||
|
{ |
||||||
|
// ACCELERATION changes VELOCITY (with respect to time)
|
||||||
|
player.dx += sin(player.angle) * 20.0f * fElapsedTime; |
||||||
|
player.dy += -cos(player.angle) * 20.0f * fElapsedTime; |
||||||
|
} |
||||||
|
|
||||||
|
if(GetKey(olc::UP).bPressed) |
||||||
|
audio.Play(sfx.at("thruster"), true); |
||||||
|
|
||||||
|
if(GetKey(olc::UP).bReleased) |
||||||
|
audio.Stop(sfx.at("thruster")); |
||||||
|
|
||||||
|
// VELOCITY changes POSITION (with respect to time)
|
||||||
|
player.x += player.dx * fElapsedTime; |
||||||
|
player.y += player.dy * fElapsedTime; |
||||||
|
|
||||||
|
// Keep ship in gamespace
|
||||||
|
WrapCoordinates(player.x, player.y, player.x, player.y); |
||||||
|
|
||||||
|
// Check ship collision with asteroids
|
||||||
|
for (auto &a : vecAsteroids) |
||||||
|
if (IsPointInsideCircle(a.x, a.y, a.nSize, player.x, player.y)) |
||||||
|
{ |
||||||
|
bDead = true; // Uh oh...
|
||||||
|
audio.Play(sfx.at("lose")); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Fire Bullet in direction of player
|
||||||
|
if (GetKey(olc::SPACE).bReleased) |
||||||
|
{ |
||||||
|
vecBullets.push_back({ 0, player.x, player.y, 150.0f * sinf(player.angle), -150.0f * cosf(player.angle), 100.0f }); |
||||||
|
audio.Play(sfx.at("laser")); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Update and draw asteroids
|
||||||
|
for (auto &a : vecAsteroids) |
||||||
|
{ |
||||||
|
// VELOCITY changes POSITION (with respect to time)
|
||||||
|
a.x += a.dx * fElapsedTime; |
||||||
|
a.y += a.dy * fElapsedTime; |
||||||
|
a.angle += 0.5f * fElapsedTime; // Add swanky rotation :)
|
||||||
|
|
||||||
|
// Asteroid coordinates are kept in game space (toroidal mapping)
|
||||||
|
WrapCoordinates(a.x, a.y, a.x, a.y); |
||||||
|
|
||||||
|
// Draw Asteroids
|
||||||
|
DrawWireFrameModel(vecModelAsteroid, a.x, a.y, a.angle, (float)a.nSize, olc::YELLOW);
|
||||||
|
} |
||||||
|
|
||||||
|
// Any new asteroids created after collision detection are stored
|
||||||
|
// in a temporary vector, so we don't interfere with the asteroids
|
||||||
|
// vector iterator in the for(auto)
|
||||||
|
std::vector<sSpaceObject> newAsteroids; |
||||||
|
|
||||||
|
// Update Bullets
|
||||||
|
for (auto &b : vecBullets) |
||||||
|
{ |
||||||
|
b.x += b.dx * fElapsedTime; |
||||||
|
b.y += b.dy * fElapsedTime; |
||||||
|
WrapCoordinates(b.x, b.y, b.x, b.y); |
||||||
|
b.angle -= 1.0f * fElapsedTime; |
||||||
|
|
||||||
|
// Check collision with asteroids
|
||||||
|
for (auto &a : vecAsteroids) |
||||||
|
{ |
||||||
|
//if (IsPointInsideRectangle(a.x, a.y, a.x + a.nSize, a.y + a.nSize, b.x, b.y))
|
||||||
|
if(IsPointInsideCircle(a.x, a.y, a.nSize, b.x, b.y)) |
||||||
|
{ |
||||||
|
// Asteroid Hit - Remove bullet
|
||||||
|
// We've already updated the bullets, so force bullet to be offscreen
|
||||||
|
// so it is cleaned up by the removal algorithm.
|
||||||
|
b.x = -100; |
||||||
|
|
||||||
|
// Create child asteroids
|
||||||
|
if (a.nSize > 4) |
||||||
|
{ |
||||||
|
float angle1 = ((float)rand() / (float)RAND_MAX) * 6.283185f; |
||||||
|
float angle2 = ((float)rand() / (float)RAND_MAX) * 6.283185f; |
||||||
|
newAsteroids.push_back({ (int)a.nSize >> 1 ,a.x, a.y, 30.0f * sinf(angle1), 30.0f * cosf(angle1), 0.0f }); |
||||||
|
newAsteroids.push_back({ (int)a.nSize >> 1 ,a.x, a.y, 30.0f * sinf(angle2), 30.0f * cosf(angle2), 0.0f }); |
||||||
|
} |
||||||
|
|
||||||
|
// Remove asteroid - Same approach as bullets
|
||||||
|
a.x = -100; |
||||||
|
nScore += 100; // Small score increase for hitting asteroid
|
||||||
|
audio.Play(sfx.at("explosion")); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Append new asteroids to existing vector
|
||||||
|
for(auto a:newAsteroids) |
||||||
|
vecAsteroids.push_back(a); |
||||||
|
|
||||||
|
// Clear up dead objects - They are out of game space
|
||||||
|
|
||||||
|
// Remove asteroids that have been blown up
|
||||||
|
if (vecAsteroids.size() > 0) |
||||||
|
{ |
||||||
|
auto i = remove_if(vecAsteroids.begin(), vecAsteroids.end(), [&](sSpaceObject o) { return (o.x < 0); }); |
||||||
|
if (i != vecAsteroids.end()) |
||||||
|
vecAsteroids.erase(i); |
||||||
|
} |
||||||
|
|
||||||
|
if (vecAsteroids.empty()) // If no asteroids, level complete! :) - you win MORE asteroids!
|
||||||
|
{ |
||||||
|
// Level Clear
|
||||||
|
nScore += 1000; // Large score for level progression
|
||||||
|
vecAsteroids.clear(); |
||||||
|
vecBullets.clear(); |
||||||
|
|
||||||
|
// Add two new asteroids, but in a place where the player is not, we'll simply
|
||||||
|
// add them 90 degrees left and right to the player, their coordinates will
|
||||||
|
// be wrapped by th enext asteroid update
|
||||||
|
vecAsteroids.push_back({ (int)16, 80.0f * sinf(player.angle - 3.14159f/2.0f) + player.x, |
||||||
|
80.0f * cosf(player.angle - 3.14159f/2.0f) + player.y, |
||||||
|
60.0f * sinf(player.angle), 60.0f*cosf(player.angle), 0.0f }); |
||||||
|
|
||||||
|
vecAsteroids.push_back({ (int)16, 80.0f * sinf(player.angle + 3.14159f/2.0f) + player.x, |
||||||
|
80.0f * cosf(player.angle + 3.14159f/2.0f) + player.y, |
||||||
|
60.0f * sinf(-player.angle), 60.0f*cosf(-player.angle), 0.0f }); |
||||||
|
} |
||||||
|
|
||||||
|
// Remove bullets that have gone off screen
|
||||||
|
if (vecBullets.size() > 0) |
||||||
|
{ |
||||||
|
auto i = remove_if(vecBullets.begin(), vecBullets.end(), [&](sSpaceObject o) { return (o.x < 1 || o.y < 1 || o.x >= ScreenWidth() - 1 || o.y >= ScreenHeight() - 1); }); |
||||||
|
if (i != vecBullets.end()) |
||||||
|
vecBullets.erase(i); |
||||||
|
} |
||||||
|
|
||||||
|
// Draw Bullets
|
||||||
|
for (auto b : vecBullets) |
||||||
|
Draw(b.x, b.y); |
||||||
|
|
||||||
|
// Draw Ship
|
||||||
|
DrawWireFrameModel(vecModelShip, player.x, player.y, player.angle); |
||||||
|
|
||||||
|
// Draw Score
|
||||||
|
DrawString(2, 2, "SCORE: " + std::to_string(nScore)); |
||||||
|
|
||||||
|
return !GetKey(olc::ESCAPE).bPressed; |
||||||
|
} |
||||||
|
|
||||||
|
void DrawWireFrameModel(const std::vector<std::pair<float, float>> &vecModelCoordinates, float x, float y, float r = 0.0f, float s = 1.0f, olc::Pixel col = olc::WHITE) |
||||||
|
{ |
||||||
|
// pair.first = x coordinate
|
||||||
|
// pair.second = y coordinate
|
||||||
|
|
||||||
|
// Create translated model vector of coordinate pairs
|
||||||
|
std::vector<std::pair<float, float>> vecTransformedCoordinates; |
||||||
|
int verts = vecModelCoordinates.size(); |
||||||
|
vecTransformedCoordinates.resize(verts); |
||||||
|
|
||||||
|
// Rotate
|
||||||
|
for (int i = 0; i < verts; i++) |
||||||
|
{ |
||||||
|
vecTransformedCoordinates[i].first = vecModelCoordinates[i].first * cosf(r) - vecModelCoordinates[i].second * sinf(r); |
||||||
|
vecTransformedCoordinates[i].second = vecModelCoordinates[i].first * sinf(r) + vecModelCoordinates[i].second * cosf(r); |
||||||
|
} |
||||||
|
|
||||||
|
// Scale
|
||||||
|
for (int i = 0; i < verts; i++) |
||||||
|
{ |
||||||
|
vecTransformedCoordinates[i].first = vecTransformedCoordinates[i].first * s; |
||||||
|
vecTransformedCoordinates[i].second = vecTransformedCoordinates[i].second * s; |
||||||
|
} |
||||||
|
|
||||||
|
// Translate
|
||||||
|
for (int i = 0; i < verts; i++) |
||||||
|
{ |
||||||
|
vecTransformedCoordinates[i].first = vecTransformedCoordinates[i].first + x; |
||||||
|
vecTransformedCoordinates[i].second = vecTransformedCoordinates[i].second + y; |
||||||
|
} |
||||||
|
|
||||||
|
// Draw Closed Polygon
|
||||||
|
for (int i = 0; i < verts + 1; i++) |
||||||
|
{ |
||||||
|
int j = (i + 1); |
||||||
|
DrawLine(vecTransformedCoordinates[i % verts].first, vecTransformedCoordinates[i % verts].second,
|
||||||
|
vecTransformedCoordinates[j % verts].first, vecTransformedCoordinates[j % verts].second, col); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
int main() |
||||||
|
{ |
||||||
|
OneLoneCoder_Asteroids game; |
||||||
|
if(game.Construct(320, 180, 4, 4)) |
||||||
|
game.Start(); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
@ -0,0 +1,4 @@ |
|||||||
|
#define OLC_PGEX_MINIAUDIO |
||||||
|
#include "olcPGEX_MiniAudio.h" |
||||||
|
|
||||||
|
|
@ -0,0 +1,3 @@ |
|||||||
|
#define OLC_PGE_APPLICATION |
||||||
|
#include "olcPixelGameEngine.h" |
||||||
|
|
Loading…
Reference in new issue