Skip to content

Commit

Permalink
3D Space Shooter
Browse files Browse the repository at this point in the history
  • Loading branch information
JiumingGo committed May 14, 2024
1 parent d6a4d60 commit b1c2419
Show file tree
Hide file tree
Showing 23 changed files with 3,736 additions and 3 deletions.
60 changes: 60 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
cmake_minimum_required(VERSION 3.12)
#-------------------------------------------------------------------------------------------
# I'm going to use vcpk in most cases for our install of 3rd party libs
# this is going to check the environment variable for CMAKE_TOOLCHAIN_FILE and this must point to where
# vcpkg.cmake is in the University this is set in your .bash_profile to
# export CMAKE_TOOLCHAIN_FILE=/public/devel/2020/vcpkg/scripts/buildsystems/vcpkg.cmake
#-------------------------------------------------------------------------------------------
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{CMAKE_TOOLCHAIN_FILE})
set(CMAKE_TOOLCHAIN_FILE $ENV{CMAKE_TOOLCHAIN_FILE})
endif()

# Name of the project
project(GameKeyControlBuild)
# This is the name of the Exe change this and it will change everywhere
set(TargetName 3DSpaceShooter)
# This will include the file NGLConfig.cmake, you need to add the location to this either using
# -DCMAKE_PREFIX_PATH=~/NGL or as a system environment variable.
find_package(NGL CONFIG REQUIRED)
# Instruct CMake to run moc automatically when needed (Qt projects only)
set(CMAKE_AUTOMOC ON)
# find Qt libs first we check for Version 6
find_package(Qt6 COMPONENTS OpenGL Widgets QUIET )
if ( Qt6_FOUND )
message("Found Qt6 Using that")
else()
message("Found Qt5 Using that")
find_package(Qt5 COMPONENTS OpenGL Widgets REQUIRED)
endif()
# use C++ 17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)
# Set the name of the executable we want to build
add_executable(${TargetName}
include/laser.h
src/laser.cpp
include/Enemy.h
src/Enemy.cpp
include/SineWaveEnemy.h
src/SineWaveEnemy.cpp
include/ShootingEnemy.h
include/EnemyLaser.h
src/ShootingEnemy.cpp
src/EnemyLaser.cpp)
target_sources(${TargetName} PRIVATE ${PROJECT_SOURCE_DIR}/src/main.cpp
${PROJECT_SOURCE_DIR}/src/NGLScene.cpp
${PROJECT_SOURCE_DIR}/src/SpaceShip.cpp
${PROJECT_SOURCE_DIR}/include/NGLScene.h
${PROJECT_SOURCE_DIR}/include/SpaceShip.h
)
target_link_libraries(${TargetName} PRIVATE NGL Qt::Widgets Qt::OpenGL)

add_custom_target(${TargetName}CopyShaders ALL
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/shaders
$<TARGET_FILE_DIR:${TargetName}>/shaders
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/models
$<TARGET_FILE_DIR:${TargetName}>/models
)
70 changes: 67 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,72 @@
# Jiuming Gong s5304091 CFGAA Assigment
## 3D Space Shooter

## _Assigment Ideas_
---

<!-- 3D car race game>
This project is based on [GameKeyControl](https://github.com/NCCA/AdvancedGameKeyControl).
The inspiration of this Project is from: [How To Make a Space Shooter in 20 Minutes(Godot Engine)](https://youtu.be/qd0UTOQ_la8?si=2K4Nh4uwkipLyo0s)
I followed this video's class design pattern and rewrote it in C++.
### Gameplay
![alt text](./image/3DSpaceShooter.png "screenshot")
---

The player uses the _**arrow-keys**_ to control a spaceship. The spaceship can only move in two dimensions. The player can press _**space**_ to fire a laser. The player needs to use the laser to kill the space troll. If the space troll reaches the bottom of the window, the player will lose 1 HP. The game is over when the player's HP reaches zero.

---

### Code Structure

---
**SpaceShip Class:**
This class handles player health and collision detection for lasers and the spaceship itself. The collision detection function will take the target object and calculate the distance using the target position and self-position. It will return if the distance is less than the collision sphere's radius. Then according to the result, it decreases the player's health.

**Laser Class:**
This class contains the `draw` and `update` functions for the laser object. The `draw` function will be called inside the Spaceship class once it shoots, and the `update` function will be called in the Spaceship class once it is instantiated. This is the base class for **EnemyLaser**.

**EnemyLaser Class:**
It is derived from the Laser class. This laser will only move down the screen.

**Enemy Class:**
The base class of all enemy classes. It contains functions like `draw`, `update` and `collision` detection. It also handles `spawn` position, `death`, and `hit` state.

**SineWaveEnemy Class:**
The subclass of Enemy class. This enemy will move they x position in sine wave pattern. The construct will take three more parameter than base class. To control amplitude ,frequency and timer.

**ShootingEnemy Class:**
The subclass of Enemy class. Every time interval it will shoot an EnemyLaser straight down.

**NGLScene:**
This source file handles every class above. `paintGL` handles every `draw` function. In `timerEvent`, it calculates and passes the delta time to every `update` function. It also handles game states like score and enemy vector array.

---

### Possible Improvement:

---

There is only one shader for every object. I could write shaders for each enemy type and spaceship. I can potentially add background texture to the game.

---

### Build

---

#### requirement:
`c++ compiler supporting C++17`
`Qt5 or Qt6`
`NGL (NCCA Graphics Library)`
`vcpkg`

to build use:
```
mkdir build
cd build
cmake -DCMAKE_TOOLCHAIN_FILE=[vcpkg toolchain location] ..
cmake --build .
```
### The video is in image/gameplayer.mp4
<video width="720" height="1280" controls>
<source src="./image/gameplay.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>

Binary file added image/3DSpaceShooter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added image/gameplay.mp4
Binary file not shown.
36 changes: 36 additions & 0 deletions include/Enemy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// Created by s5304091
//

#ifndef ENEMY_H
#define ENEMY_H

#include <ngl/Vec3.h>
#include <ngl/Mat4.h>
class Enemy{
public:
explicit Enemy(const ngl::Vec3 &startPosition, float speed = 20.0f, int health = 1,float radius = 1.5f);
virtual ~Enemy() = default;
virtual void update(float deltaTime);
virtual void draw(const ngl::Mat4 &_view , const ngl::Mat4 &_project);
[[nodiscard]] ngl::Vec3 getPosition() const;
static Enemy spawnAt(const ngl::Vec3& position);
bool checkCollision(const ngl::Vec3 &otherPos, float otherRadius);
void decreaseHealth(int amount);
float get_Radius();
bool isDestroyed();
void getHit();
[[nodiscard]] bool hited() const;
protected:
ngl::Vec3 m_pos;
float m_speed;
//collision detection
float m_radius;
int m_health;
bool m_isHit;
//Helper function for derived classes to use
virtual void move(float deltaTime);
};


#endif //ENEMY_H
16 changes: 16 additions & 0 deletions include/EnemyLaser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Created by s5304091
//

#ifndef ENEMYLASER_H
#define ENEMYLASER_H

#include "laser.h"

class EnemyLaser: public Laser{
public:
EnemyLaser(const ngl::Vec3 &pos, const ngl::Vec3 &dir, float speed);
void update(float deltaTime) override;
};

#endif //ENEMYLASER_H
174 changes: 174 additions & 0 deletions include/NGLScene.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#ifndef NGLSCENE_H_
#define NGLSCENE_H_
#include "SpaceShip.h"
#include "Enemy.h"
#include "SineWaveEnemy.h"
#include "ShootingEnemy.h"
#include <ngl/Text.h>
#include "WindowParams.h"
#include <QOpenGLWindow>
#include <QElapsedTimer>
#include <QSet>
#include <memory>
#include <QImage>
#include <QOpenGLTexture>
//----------------------------------------------------------------------------------------------------------------------
/// @file NGLScene.h
/// @brief this class inherits from the Qt OpenGLWindow and allows us to use NGL to draw OpenGL
/// @author Jonathan Macey
/// @version 1.0
/// @date 10/9/13
/// Revision History :
/// This is an initial version used for the new NGL6 / Qt 5 demos
/// @class NGLScene
/// @brief our main glwindow widget for NGL applications all drawing elements are
/// put in this file
//----------------------------------------------------------------------------------------------------------------------

class NGLScene : public QOpenGLWindow
{
public:
//----------------------------------------------------------------------------------------------------------------------
/// @brief ctor for our NGL drawing class
/// @param [in] parent the parent window to the class
//----------------------------------------------------------------------------------------------------------------------
NGLScene();
//----------------------------------------------------------------------------------------------------------------------
/// @brief dtor must close down ngl and release OpenGL resources
//----------------------------------------------------------------------------------------------------------------------
~NGLScene();
//----------------------------------------------------------------------------------------------------------------------
/// @brief the initialize class is called once when the window is created and we have a valid GL context
/// use this to setup any default GL stuff
//----------------------------------------------------------------------------------------------------------------------
void initializeGL();
//----------------------------------------------------------------------------------------------------------------------
/// @brief this is called everytime we want to draw the scene
//----------------------------------------------------------------------------------------------------------------------
void paintGL();
//----------------------------------------------------------------------------------------------------------------------
/// @brief this is called everytime we resize
//----------------------------------------------------------------------------------------------------------------------
void resizeGL(int _w, int _h);

//Method to get elapsed time since the timer was started
float getElapsedTime();
//Method to spawn enemy
void spawnEnemy();
//Method to spawn sine wave enemy
void spawnSineEnemy();
//Method to spawn shooting enemy
void spawnShootingEnemy();
//To display player score
int m_score = 0;
void checkGameOver();

private:
//----------------------------------------------------------------------------------------------------------------------
/// the new add variables for game control
//----------------------------------------------------------------------------------------------------------------------
bool m_spacePressed = false;
QElapsedTimer m_timer;
bool m_gameOver = false;


//----------------------------------------------------------------------------------------------------------------------
/// @brief the windows params such as mouse and rotations etc
//----------------------------------------------------------------------------------------------------------------------
WinParams m_win;
//----------------------------------------------------------------------------------------------------------------------
/// @brief Our Camera
//----------------------------------------------------------------------------------------------------------------------
ngl::Mat4 m_view;
ngl::Mat4 m_project;
//----------------------------------------------------------------------------------------------------------------------
/// @brief the model position for mouse movement
//----------------------------------------------------------------------------------------------------------------------
ngl::Vec3 m_modelPos;
//----------------------------------------------------------------------------------------------------------------------
/// @brief a timer triggered by the startTimer call in the ctor this is called
/// to update the ship position based on the key presses
//----------------------------------------------------------------------------------------------------------------------
int m_updateShipTimer;
//----------------------------------------------------------------------------------------------------------------------
/// @brief we will draw with a different timer to the update
//----------------------------------------------------------------------------------------------------------------------
int m_redrawTimer;
//timer for spawn enemies
int m_enemySpawnTimer;
//timer for spawn sine enemies
int m_sineSpawnTimer;
//timer for spawn shooting enemies
int m_shooterSpawnTimer;
//----------------------------------------------------------------------------------------------------------------------
/// @brief a pointer to our spaceship
//----------------------------------------------------------------------------------------------------------------------
std::unique_ptr<SpaceShip> m_ship;
//----------------------------------------------------------------------------------------------------------------------
/// @brief the keys being pressed
//----------------------------------------------------------------------------------------------------------------------
QSet<Qt::Key> m_keysPressed;
//----------------------------------------------------------------------------------------------------------------------
/// @brief a pointer to our enemies
//----------------------------------------------------------------------------------------------------------------------
std::vector<Enemy> m_enemies;
std::vector<SineWaveEnemy> m_sineWaveEnemies;
std::vector<ShootingEnemy> m_shootEnemies;

//----------------------------------------------------------------------------------------------------------------------
/// @brief method to load transform matrices to the shader
//----------------------------------------------------------------------------------------------------------------------
void loadMatricesToShader();
//----------------------------------------------------------------------------------------------------------------------
/// @brief this method is called every time a mouse is moved
/// @param _event the Qt Event structure
//----------------------------------------------------------------------------------------------------------------------
void mouseMoveEvent (QMouseEvent * _event );
//----------------------------------------------------------------------------------------------------------------------
/// @brief this method is called everytime the mouse button is pressed
/// inherited from QObject and overridden here.
/// @param _event the Qt Event structure
//----------------------------------------------------------------------------------------------------------------------
void mousePressEvent ( QMouseEvent *_event);
//----------------------------------------------------------------------------------------------------------------------
/// @brief this method is called everytime the mouse button is released
/// inherited from QObject and overridden here.
/// @param _event the Qt Event structure
//----------------------------------------------------------------------------------------------------------------------
void mouseReleaseEvent ( QMouseEvent *_event );

//----------------------------------------------------------------------------------------------------------------------
/// @brief this method is called everytime the mouse wheel is moved
/// inherited from QObject and overridden here.
/// @param _event the Qt Event structure
//----------------------------------------------------------------------------------------------------------------------
void wheelEvent( QWheelEvent *_event);

//----------------------------------------------------------------------------------------------------------------------
/// @brief processKeyDown passed from the main window class
/// @param *_event a pointer to the QKeyEvent passed from main window
/// class
//----------------------------------------------------------------------------------------------------------------------
void keyPressEvent(QKeyEvent *_event );
//----------------------------------------------------------------------------------------------------------------------
/// @brief processKeyUp passed from the main window class
/// @param *_event a pointer to the QKeyEvent passed from main window
/// class
//----------------------------------------------------------------------------------------------------------------------
void keyReleaseEvent(QKeyEvent *_event );
//----------------------------------------------------------------------------------------------------------------------
/// @brief called when the timer triggers used to update and draw
/// @param *_event a pointer to the timer event id
//----------------------------------------------------------------------------------------------------------------------
void timerEvent( QTimerEvent *_event);
//----------------------------------------------------------------------------------------------------------------------
/// @brief update ship based on stored key movements
//----------------------------------------------------------------------------------------------------------------------

void moveShip();

};



#endif
24 changes: 24 additions & 0 deletions include/ShootingEnemy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// Created by s5304091
//

#ifndef SHOOTINGENEMY_H
#define SHOOTINGENEMY_H
#include "Enemy.h"
#include "EnemyLaser.h"
#include "SpaceShip.h"
class ShootingEnemy : public Enemy
{
public:
ShootingEnemy(const ngl::Vec3 &startPosition, float speed, int health, float radius);
void update(float deltaTime) override;
void firelaser();
[[nodiscard]] const std::vector<EnemyLaser>& getLaser() const;
bool checkLaserCollision(SpaceShip &ship);
private:
std::vector<EnemyLaser> m_lasers;
float m_fireRate;
float m_timeSinceLastShot;
};

#endif //SHOOTINGENEMY_H
Loading

0 comments on commit b1c2419

Please sign in to comment.