Started encpsulation of player logic
This commit is contained in:
89
TWANG32/Player.h
Normal file
89
TWANG32/Player.h
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
class Player
|
||||
{
|
||||
public:
|
||||
Player(int[3], int, int);
|
||||
void Lives(int);
|
||||
int Lives();
|
||||
void Kill();
|
||||
bool Alive();
|
||||
void moveto(int);
|
||||
void moveby(int);
|
||||
int color[3];
|
||||
int position;
|
||||
bool attacking;
|
||||
int last_attack;
|
||||
void updateState(bool tilted, bool wobbled, int time);
|
||||
void startAttack(int time);
|
||||
int _lastState; // 0-> idle; 1-> move; 2 -> attack
|
||||
private:
|
||||
int _lives;
|
||||
int _state;
|
||||
|
||||
int _attackDuration;
|
||||
};
|
||||
|
||||
Player::Player(int player_color[3], int lives, int attackDuration){
|
||||
_lives = lives;
|
||||
attacking = false;
|
||||
|
||||
color[0] = player_color[0];
|
||||
color[1] = player_color[1];
|
||||
color[2] = player_color[2];
|
||||
|
||||
_attackDuration = attackDuration;
|
||||
|
||||
_lastState = 0; // start as idle;
|
||||
}
|
||||
|
||||
void Player::updateState(bool tilted, bool wobbled, int time) {
|
||||
|
||||
// attack timed out
|
||||
if(attacking && last_attack+_attackDuration < time) attacking = false;
|
||||
|
||||
// no longer attacking
|
||||
if (!wobbled) attacking = false;
|
||||
|
||||
_lastState = 0;
|
||||
if (tilted) _lastState = 1; // moving
|
||||
if (wobbled) _lastState = 2; // attacking
|
||||
}
|
||||
|
||||
void Player::startAttack(int time){
|
||||
// if already attacking just return
|
||||
if (attacking) return;
|
||||
|
||||
// I got tired of attacking, I should be idle or moving for a little before attacking again.
|
||||
if (_lastState == 2) return;
|
||||
|
||||
last_attack = time;
|
||||
attacking = true;
|
||||
}
|
||||
|
||||
void Player::Lives(int n){
|
||||
_lives = n;
|
||||
}
|
||||
|
||||
bool Player::Alive(){
|
||||
return _lives > 0;
|
||||
}
|
||||
|
||||
void Player::Kill(){
|
||||
_lives--;
|
||||
if (_lives < 0) _lives = 0;
|
||||
}
|
||||
|
||||
int Player::Lives(){
|
||||
return _lives;
|
||||
}
|
||||
|
||||
void Player::moveby(int amount){
|
||||
position += amount;
|
||||
if (position<0) position=0;
|
||||
}
|
||||
|
||||
void Player::moveto(int amount){
|
||||
position = amount;
|
||||
if (position<0) position=0;
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
|
||||
Usage Notes:
|
||||
- Changes attack model and added Player class
|
||||
- Changes to LED strip and other hardware are in config.h
|
||||
- Change the strip type to what you are using and compile/load firmware
|
||||
- Use Serial port or Wifi to set your strip length.
|
||||
@@ -42,6 +43,7 @@
|
||||
#include "twang_mpu.h"
|
||||
#endif
|
||||
#include "Enemy.h"
|
||||
#include "Player.h"
|
||||
#include "Particle.h"
|
||||
#include "Spawner.h"
|
||||
#include "Lava.h"
|
||||
@@ -75,9 +77,9 @@ int joystickWobble = 0; // Stores the max amount of acceleration (wob
|
||||
#define DEFAULT_ATTACK_WIDTH 70 // Width of the wobble attack, world is 1000 wide
|
||||
int attack_width = DEFAULT_ATTACK_WIDTH;
|
||||
#define ATTACK_DURATION 1000 // Duration of a wobble attack (ms)
|
||||
long attackMillis = 0; // Time the attack started
|
||||
bool attacking = 0; // Is the attack in progress?
|
||||
bool canAttackAgain = 0; // Have I finished my previous attack?
|
||||
//long attackMillis = 0; // Time the attack started
|
||||
//bool attacking = 0; // Is the attack in progress?
|
||||
//bool canAttackAgain = 0; // Have I finished my previous attack?
|
||||
#define BOSS_WIDTH 40
|
||||
|
||||
// TODO all animation durations should be defined rather than literals
|
||||
@@ -135,6 +137,9 @@ Conveyor conveyorPool[CONVEYOR_COUNT] = {
|
||||
|
||||
Boss boss = Boss();
|
||||
|
||||
int pcolor[3] = {0,255,0};
|
||||
Player player = Player(pcolor, LIVES_PER_LEVEL, ATTACK_DURATION);
|
||||
|
||||
enum stages {
|
||||
STARTUP,
|
||||
PLAY,
|
||||
@@ -146,11 +151,8 @@ enum stages {
|
||||
} stage;
|
||||
|
||||
long stageStartTime; // Stores the time the stage changed for stages that are time based
|
||||
int playerPosition; // Stores the player position
|
||||
int playerPositionModifier; // +/- adjustment to player position
|
||||
bool playerAlive;
|
||||
long killTime;
|
||||
int lives = LIVES_PER_LEVEL;
|
||||
bool lastLevel = false;
|
||||
|
||||
int score = 0;
|
||||
@@ -241,7 +243,7 @@ void setup() {
|
||||
|
||||
stage = STARTUP;
|
||||
stageStartTime = millis();
|
||||
lives = user_settings.lives_per_level;
|
||||
player.Lives ( user_settings.lives_per_level );
|
||||
}
|
||||
|
||||
void loop() {
|
||||
@@ -252,7 +254,7 @@ void loop() {
|
||||
checkSerialInput();
|
||||
|
||||
if(stage == PLAY){
|
||||
if(attacking){
|
||||
if(player.attacking){
|
||||
SFXattacking();
|
||||
}else{
|
||||
SFXtilt(joystickTilt);
|
||||
@@ -270,7 +272,7 @@ void loop() {
|
||||
previousMillis = mm;
|
||||
|
||||
if((abs(joystickTilt) > user_settings.joystick_deadzone) ||
|
||||
(joystickWobble >= user_settings.attack_threshold))
|
||||
(abs(joystickWobble) >= user_settings.attack_threshold))
|
||||
{
|
||||
lastInputTime = mm;
|
||||
if(stage == SCREENSAVER){
|
||||
@@ -300,48 +302,38 @@ void loop() {
|
||||
}
|
||||
}else if(stage == PLAY){
|
||||
// PLAYING
|
||||
if(attacking && attackMillis+ATTACK_DURATION < mm) {
|
||||
attacking = 0;
|
||||
canAttackAgain = 0;
|
||||
}
|
||||
|
||||
if(joystickWobble < user_settings.attack_threshold){
|
||||
attacking = 0;
|
||||
canAttackAgain = 1;
|
||||
}
|
||||
if (joystickWobble >= user_settings.attack_threshold) player.startAttack(mm);
|
||||
|
||||
// If not attacking, check if they should be
|
||||
if(!attacking && canAttackAgain && (joystickWobble >= user_settings.attack_threshold)){
|
||||
attackMillis = mm;
|
||||
attacking = 1;
|
||||
}
|
||||
player.updateState(
|
||||
abs(joystickTilt) > user_settings.joystick_deadzone,
|
||||
abs(joystickWobble) >= user_settings.attack_threshold,
|
||||
mm);
|
||||
|
||||
// If still not attacking, move!
|
||||
playerPosition += playerPositionModifier;
|
||||
if(!attacking){
|
||||
player.moveby(playerPositionModifier);
|
||||
if(!player.attacking){
|
||||
SFXtilt(joystickTilt);
|
||||
//int moveAmount = (joystickTilt/6.0); // 6.0 is ideal at 16ms interval (6.0 / (16.0 / MIN_REDRAW_INTERVAL))
|
||||
int moveAmount = (joystickTilt/(6.0)); // 6.0 is ideal at 16ms interval
|
||||
if(DIRECTION) moveAmount = -moveAmount;
|
||||
moveAmount = constrain(moveAmount, -MAX_PLAYER_SPEED, MAX_PLAYER_SPEED);
|
||||
|
||||
playerPosition -= moveAmount;
|
||||
if(playerPosition < 0)
|
||||
playerPosition = 0;
|
||||
player.moveby( -moveAmount );
|
||||
|
||||
// stop player from leaving if boss is alive
|
||||
if (boss.Alive() && playerPosition >= VIRTUAL_LED_COUNT) // move player back
|
||||
playerPosition = 999; //(user_settings.led_count - 1) * (1000.0/user_settings.led_count);
|
||||
if (boss.Alive() && player.position >= VIRTUAL_LED_COUNT) // move player back
|
||||
player.moveto( 999 ); //(user_settings.led_count - 1) * (1000.0/user_settings.led_count);
|
||||
|
||||
if(playerPosition >= VIRTUAL_LED_COUNT && !boss.Alive()) {
|
||||
if(player.position >= VIRTUAL_LED_COUNT && !boss.Alive()) {
|
||||
// Reached exit!
|
||||
levelComplete();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(inLava(playerPosition)){
|
||||
die();
|
||||
if(inLava(player.position)){
|
||||
die(player);
|
||||
}
|
||||
|
||||
// Ticks and draw calls
|
||||
@@ -351,13 +343,13 @@ void loop() {
|
||||
tickBoss();
|
||||
tickLava();
|
||||
tickEnemies();
|
||||
drawPlayer();
|
||||
drawAttack();
|
||||
drawPlayer(player);
|
||||
drawAttack(player);
|
||||
drawExit();
|
||||
}else if(stage == DEAD){
|
||||
// DEAD
|
||||
FastLED.clear();
|
||||
tickDie(mm);
|
||||
tickDie(player, mm);
|
||||
if(!tickParticles()){
|
||||
loadLevel();
|
||||
}
|
||||
@@ -377,7 +369,7 @@ void loop() {
|
||||
// restart from the beginning
|
||||
stage = STARTUP;
|
||||
stageStartTime = millis();
|
||||
lives = user_settings.lives_per_level;
|
||||
player.Lives ( user_settings.lives_per_level );
|
||||
}
|
||||
}
|
||||
//FastLED.show();
|
||||
@@ -393,12 +385,11 @@ void loadLevel(){
|
||||
FastLED.setBrightness(user_settings.led_brightness);
|
||||
updateLives();
|
||||
cleanupLevel();
|
||||
playerAlive = 1;
|
||||
lastLevel = false; // this gets changed on the boss level
|
||||
|
||||
/// Defaults...OK to change the following items in the levels below
|
||||
attack_width = DEFAULT_ATTACK_WIDTH;
|
||||
playerPosition = 0;
|
||||
player.moveto( 0 );
|
||||
|
||||
/* ==== Level Editing Guide ===============
|
||||
Level creation is done by adding to or editing the switch statement below
|
||||
@@ -451,7 +442,7 @@ void loadLevel(){
|
||||
===== Other things you can adjust per level ================
|
||||
|
||||
Player Start position:
|
||||
playerPosition = xxx;
|
||||
player.moveto( xxx );
|
||||
|
||||
|
||||
The size of the TWANG attack
|
||||
@@ -461,7 +452,7 @@ void loadLevel(){
|
||||
*/
|
||||
switch(levelNumber){
|
||||
case 0: // basic introduction
|
||||
playerPosition = 200;
|
||||
player.moveto( 200 );
|
||||
spawnEnemy(1, 0, 0, 0);
|
||||
break;
|
||||
case 1:
|
||||
@@ -508,7 +499,7 @@ void loadLevel(){
|
||||
break;
|
||||
case 8:
|
||||
// lava moving up
|
||||
playerPosition = 200;
|
||||
player.moveto( 200 );
|
||||
spawnLava(10, 180, 2000, 2000, 0, Lava::OFF, 0, 0.5);
|
||||
spawnEnemy(350, 0, 1, 0);
|
||||
spawnPool[0].Spawn(1000, 5500, 3, 0, 0);
|
||||
@@ -610,7 +601,7 @@ void spawnEnemy(int pos, int dir, int speed, int wobble){
|
||||
for(int e = 0; e<ENEMY_COUNT; e++){ // look for one that is not alive for a place to add one
|
||||
if(!enemyPool[e].Alive()){
|
||||
enemyPool[e].Spawn(pos, dir, speed, wobble);
|
||||
enemyPool[e].playerSide = pos > playerPosition?1:-1;
|
||||
enemyPool[e].playerSide = pos > player.position?1:-1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -662,7 +653,7 @@ void levelComplete(){
|
||||
}
|
||||
if (levelNumber != 0) // no points for the first level
|
||||
{
|
||||
score = score + (lives * 10); //
|
||||
score = score + (player.Lives() * 10); //
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,11 +663,11 @@ void nextLevel(){
|
||||
if(lastLevel) {
|
||||
stage = STARTUP;
|
||||
stageStartTime = millis();
|
||||
lives = user_settings.lives_per_level;
|
||||
player.Lives ( user_settings.lives_per_level );
|
||||
|
||||
}
|
||||
else {
|
||||
lives = user_settings.lives_per_level;
|
||||
player.Lives ( user_settings.lives_per_level );
|
||||
loadLevel();
|
||||
}
|
||||
}
|
||||
@@ -687,19 +678,19 @@ void gameOver(){
|
||||
loadLevel();
|
||||
}
|
||||
|
||||
void die(){
|
||||
playerAlive = 0;
|
||||
if(levelNumber > 0)
|
||||
lives --;
|
||||
void die(Player p){
|
||||
|
||||
if(lives == 0){
|
||||
if(levelNumber > 0)
|
||||
p.Kill();
|
||||
|
||||
if(!player.Alive()){
|
||||
stage = GAMEOVER;
|
||||
stageStartTime = millis();
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int p = 0; p < PARTICLE_COUNT; p++){
|
||||
particlePool[p].Spawn(playerPosition);
|
||||
for(int ip = 0; ip < PARTICLE_COUNT; ip++){
|
||||
particlePool[ip].Spawn(p.position);
|
||||
}
|
||||
stageStartTime = millis();
|
||||
stage = DEAD;
|
||||
@@ -754,8 +745,8 @@ void tickEnemies(){
|
||||
if(enemyPool[i].Alive()){
|
||||
enemyPool[i].Tick();
|
||||
// Hit attack?
|
||||
if(attacking){
|
||||
if(enemyPool[i]._pos > playerPosition-(attack_width/2) && enemyPool[i]._pos < playerPosition+(attack_width/2)){
|
||||
if(player.attacking){
|
||||
if(enemyPool[i]._pos > player.position-(attack_width/2) && enemyPool[i]._pos < player.position+(attack_width/2)){
|
||||
enemyPool[i].Kill();
|
||||
SFXkill();
|
||||
}
|
||||
@@ -770,10 +761,10 @@ void tickEnemies(){
|
||||
}
|
||||
// Hit player?
|
||||
if(
|
||||
(enemyPool[i].playerSide == 1 && enemyPool[i]._pos <= playerPosition) ||
|
||||
(enemyPool[i].playerSide == -1 && enemyPool[i]._pos >= playerPosition)
|
||||
(enemyPool[i].playerSide == 1 && enemyPool[i]._pos <= player.position) ||
|
||||
(enemyPool[i].playerSide == -1 && enemyPool[i]._pos >= player.position)
|
||||
){
|
||||
die();
|
||||
die(player);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -789,15 +780,15 @@ void tickBoss(){
|
||||
leds[i] %= 100;
|
||||
}
|
||||
// CHECK COLLISION
|
||||
if(getLED(playerPosition) > getLED(boss._pos - BOSS_WIDTH/2) && getLED(playerPosition) < getLED(boss._pos + BOSS_WIDTH)){
|
||||
die();
|
||||
if(getLED(player.position) > getLED(boss._pos - BOSS_WIDTH/2) && getLED(player.position) < getLED(boss._pos + BOSS_WIDTH)){
|
||||
die(player);
|
||||
return;
|
||||
}
|
||||
// CHECK FOR ATTACK
|
||||
if(attacking){
|
||||
if(player.attacking){
|
||||
if(
|
||||
(getLED(playerPosition+(attack_width/2)) >= getLED(boss._pos - BOSS_WIDTH/2) && getLED(playerPosition+(attack_width/2)) <= getLED(boss._pos + BOSS_WIDTH/2)) ||
|
||||
(getLED(playerPosition-(attack_width/2)) <= getLED(boss._pos + BOSS_WIDTH/2) && getLED(playerPosition-(attack_width/2)) >= getLED(boss._pos - BOSS_WIDTH/2))
|
||||
(getLED(player.position+(attack_width/2)) >= getLED(boss._pos - BOSS_WIDTH/2) && getLED(player.position+(attack_width/2)) <= getLED(boss._pos + BOSS_WIDTH/2)) ||
|
||||
(getLED(player.position-(attack_width/2)) <= getLED(boss._pos + BOSS_WIDTH/2) && getLED(player.position-(attack_width/2)) >= getLED(boss._pos - BOSS_WIDTH/2))
|
||||
){
|
||||
boss.Hit();
|
||||
if(boss.Alive()){
|
||||
@@ -811,8 +802,8 @@ void tickBoss(){
|
||||
}
|
||||
}
|
||||
|
||||
void drawPlayer(){
|
||||
leds[getLED(playerPosition)] = CRGB(0, 255, 0);
|
||||
void drawPlayer(Player p){
|
||||
leds[getLED(p.position)] = CRGB(p.color[0], p.color[1], p.color[2]);
|
||||
}
|
||||
|
||||
void drawExit(){
|
||||
@@ -918,7 +909,7 @@ void tickConveyors(){
|
||||
leds[led] = CRGB(0, 0, b);
|
||||
}
|
||||
|
||||
if(playerPosition > conveyorPool[i]._startPoint && playerPosition < conveyorPool[i]._endPoint){
|
||||
if(player.position > conveyorPool[i]._startPoint && player.position < conveyorPool[i]._endPoint){
|
||||
playerPositionModifier = speed;
|
||||
}
|
||||
}
|
||||
@@ -980,7 +971,7 @@ void tickBossKilled(long mm) // boss funeral
|
||||
}
|
||||
}
|
||||
|
||||
void tickDie(long mm) { // a short bright explosion...particles persist after it.
|
||||
void tickDie(Player p, long mm) { // a short bright explosion...particles persist after it.
|
||||
const int duration = 200; // milliseconds
|
||||
const int width = 20; // half width of the explosion
|
||||
|
||||
@@ -989,14 +980,14 @@ void tickDie(long mm) { // a short bright explosion...particles persist after it
|
||||
int brightness = map((mm-stageStartTime), 0, duration, 255, 150); // this allows a fade from white to red
|
||||
|
||||
// fill up
|
||||
int n = _max(map(((mm-stageStartTime)), 0, duration, getLED(playerPosition), getLED(playerPosition)+width), 0);
|
||||
for(int i = getLED(playerPosition); i<= n; i++){
|
||||
int n = _max(map(((mm-stageStartTime)), 0, duration, getLED(p.position), getLED(p.position)+width), 0);
|
||||
for(int i = getLED(p.position); i<= n; i++){
|
||||
leds[i] = CRGB(255, brightness, brightness);
|
||||
}
|
||||
|
||||
// fill to down
|
||||
n = _max(map(((mm-stageStartTime)), 0, duration, getLED(playerPosition), getLED(playerPosition)-width), 0);
|
||||
for(int i = getLED(playerPosition); i>= n; i--){
|
||||
n = _max(map(((mm-stageStartTime)), 0, duration, getLED(p.position), getLED(p.position)-width), 0);
|
||||
for(int i = getLED(p.position); i>= n; i--){
|
||||
leds[i] = CRGB(255, brightness, brightness);
|
||||
}
|
||||
}
|
||||
@@ -1009,13 +1000,13 @@ void tickGameover(long mm) {
|
||||
if(stageStartTime+GAMEOVER_SPREAD_DURATION > mm) // Spread red from player position to top and bottom
|
||||
{
|
||||
// fill to top
|
||||
int n = _max(map(((mm-stageStartTime)), 0, GAMEOVER_SPREAD_DURATION, getLED(playerPosition), user_settings.led_count), 0);
|
||||
for(int i = getLED(playerPosition); i<= n; i++){
|
||||
int n = _max(map(((mm-stageStartTime)), 0, GAMEOVER_SPREAD_DURATION, getLED(player.position), user_settings.led_count), 0);
|
||||
for(int i = getLED(player.position); i<= n; i++){
|
||||
leds[i] = CRGB(255, 0, 0);
|
||||
}
|
||||
// fill to bottom
|
||||
n = _max(map(((mm-stageStartTime)), 0, GAMEOVER_SPREAD_DURATION, getLED(playerPosition), 0), 0);
|
||||
for(int i = getLED(playerPosition); i>= n; i--){
|
||||
n = _max(map(((mm-stageStartTime)), 0, GAMEOVER_SPREAD_DURATION, getLED(player.position), 0), 0);
|
||||
for(int i = getLED(player.position); i>= n; i--){
|
||||
leds[i] = CRGB(255, 0, 0);
|
||||
}
|
||||
SFXgameover();
|
||||
@@ -1067,7 +1058,7 @@ void drawLives()
|
||||
FastLED.clear();
|
||||
|
||||
int pos = 0;
|
||||
for (int i = 0; i < lives; i++)
|
||||
for (int i = 0; i < player.Lives(); i++)
|
||||
{
|
||||
for (int j=0; j<4; j++)
|
||||
{
|
||||
@@ -1084,21 +1075,21 @@ void drawLives()
|
||||
|
||||
|
||||
|
||||
void drawAttack(){
|
||||
if(!attacking) return;
|
||||
int n = map(millis() - attackMillis, 0, ATTACK_DURATION, 100, 5);
|
||||
for(int i = getLED(playerPosition-(attack_width/2))+1; i<=getLED(playerPosition+(attack_width/2))-1; i++){
|
||||
void drawAttack(Player p){
|
||||
if(!p.attacking) return;
|
||||
int n = map(millis() - p.last_attack, 0, ATTACK_DURATION, 100, 5);
|
||||
for(int i = getLED(p.position-(attack_width/2))+1; i<=getLED(p.position+(attack_width/2))-1; i++){
|
||||
leds[i] = CRGB(0, 0, n);
|
||||
}
|
||||
if(n > 90) {
|
||||
n = 255;
|
||||
leds[getLED(playerPosition)] = CRGB(255, 255, 255);
|
||||
leds[getLED(p.position)] = CRGB(255, 255, 255);
|
||||
}else{
|
||||
n = 0;
|
||||
leds[getLED(playerPosition)] = CRGB(0, 255, 0);
|
||||
leds[getLED(p.position)] = CRGB(0, 255, 0);
|
||||
}
|
||||
leds[getLED(playerPosition-(attack_width/2))] = CRGB(n, n, 255);
|
||||
leds[getLED(playerPosition+(attack_width/2))] = CRGB(n, n, 255);
|
||||
leds[getLED(p.position-(attack_width/2))] = CRGB(n, n, 255);
|
||||
leds[getLED(p.position+(attack_width/2))] = CRGB(n, n, 255);
|
||||
}
|
||||
|
||||
int getLED(int pos){
|
||||
|
||||
Reference in New Issue
Block a user