mirror of
https://github.com/sigonasr2/hamster.git
synced 2025-10-18 07:02:46 -05:00
Initial commit
This commit is contained in:
commit
278edfcb2b
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -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.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -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.
|
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
build
|
||||
linux-build
|
||||
emscripten-build
|
||||
nmake-build
|
||||
mingw-build
|
||||
vs-build
|
||||
.vscode
|
||||
.cache
|
292
CMakeLists.txt
Normal file
292
CMakeLists.txt
Normal file
@ -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()
|
69
LICENSE
Normal file
69
LICENSE
Normal file
@ -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.
|
217
README.md
Normal file
217
README.md
Normal file
@ -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.
|
||||
|
0
assets/.keepme
Normal file
0
assets/.keepme
Normal file
BIN
assets/gfx/space.png
Normal file
BIN
assets/gfx/space.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
BIN
assets/sounds/Explosions1.wav
Executable file
BIN
assets/sounds/Explosions1.wav
Executable file
Binary file not shown.
BIN
assets/sounds/Laser_Shoot11.wav
Executable file
BIN
assets/sounds/Laser_Shoot11.wav
Executable file
Binary file not shown.
BIN
assets/sounds/bg-music.wav
Executable file
BIN
assets/sounds/bg-music.wav
Executable file
Binary file not shown.
BIN
assets/sounds/lose9.wav
Executable file
BIN
assets/sounds/lose9.wav
Executable file
Binary file not shown.
BIN
assets/sounds/thruster.wav
Normal file
BIN
assets/sounds/thruster.wav
Normal file
Binary file not shown.
92621
include/miniaudio.h
Normal file
92621
include/miniaudio.h
Normal file
File diff suppressed because it is too large
Load Diff
477
include/olcPGEX_MiniAudio.h
Normal file
477
include/olcPGEX_MiniAudio.h
Normal file
@ -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
|
6751
include/olcPixelGameEngine.h
Normal file
6751
include/olcPixelGameEngine.h
Normal file
File diff suppressed because it is too large
Load Diff
364
src/main.cpp
Normal file
364
src/main.cpp
Normal file
@ -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;
|
||||
}
|
||||
|
4
src/olcPGEX_MiniAudio.cpp
Normal file
4
src/olcPGEX_MiniAudio.cpp
Normal file
@ -0,0 +1,4 @@
|
||||
#define OLC_PGEX_MINIAUDIO
|
||||
#include "olcPGEX_MiniAudio.h"
|
||||
|
||||
|
3
src/olcPixelGameEngine.cpp
Normal file
3
src/olcPixelGameEngine.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
Loading…
x
Reference in New Issue
Block a user