Skip to content

Commit

Permalink
Implement custom entity for toriel fireball
Browse files Browse the repository at this point in the history
  • Loading branch information
rukai committed Sep 5, 2020
1 parent 2b3b487 commit a9981f4
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 30 deletions.
4 changes: 2 additions & 2 deletions canon_collision/src/collision/collision_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ pub enum CollisionResult {
HitAtk { hitbox: HitBox, entity_defend_i: EntityKey, point: (f32, f32) },
HitShieldAtk { hitbox: HitBox, power_shield: Option<PowerShield>, entity_defend_i: EntityKey },
HitShieldDef { hitbox: HitBox, power_shield: Option<PowerShield>, entity_atk_i: EntityKey },
ReflectDef (HitBox), // TODO: add further details required for recreating projectile
ReflectAtk (HitBox),
ReflectDef (HitBox),
ReflectAtk { hitbox: HitBox, entity_def_i: EntityKey },
AbsorbDef (HitBox),
AbsorbAtk (HitBox),
GrabDef (EntityKey),
Expand Down
23 changes: 18 additions & 5 deletions canon_collision/src/entity/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ impl Item {
ItemAction::Held => { }
ItemAction::Spawn |
ItemAction::Idle => {
self.owner_id = None;
self.body.apply_friction_strong(&context.entity_def);
}

Expand Down Expand Up @@ -115,7 +116,7 @@ impl Item {
})
}

pub fn step_collision(&mut self, col_results: &[CollisionResult]) -> Option<ActionResult> {
pub fn step_collision(&mut self, context: &mut StepContext, state: &ActionState, col_results: &[CollisionResult]) -> Option<ActionResult> {
let mut set_action = None;

for col_result in col_results {
Expand All @@ -124,16 +125,28 @@ impl Item {
set_action = ActionResult::set_action(ItemAction::Fall);
}
&CollisionResult::HitAtk { .. } => {
// TODO: implement better bounce logic (put this logic in the Body)
self.body.x_vel *= -0.5;
self.body.y_vel *= -0.5;
set_action = ActionResult::set_action(ItemAction::Fall);
}
&CollisionResult::HitShieldAtk { .. } => {
&CollisionResult::HitDef { ref hitbox, ref hurtbox, entity_atk_i } => {
let action_frame = state.get_entity_frame(&context.entity_defs[state.entity_def_key.as_ref()]);
let kb_vel_mult = 1.0;
self.body.launch(context, state, action_frame, hitbox, hurtbox, entity_atk_i, kb_vel_mult);
set_action = ActionResult::set_action(ItemAction::Fall);
}
&CollisionResult::ReflectAtk { .. } => {
// TODO
&CollisionResult::HitShieldAtk { .. } => {
// TODO: implement better bounce logic (put this logic in the Body)
self.body.x_vel *= -0.5;
self.body.y_vel *= -0.5;
set_action = ActionResult::set_action(ItemAction::Fall);
}
&CollisionResult::AbsorbAtk { .. } => {
&CollisionResult::ReflectAtk { entity_def_i, .. } => {
// TODO: implement better reflect logic, maybe the reflect hitbox should have a `set_angle: Option<f32>`
self.owner_id = context.entities.get(entity_def_i).and_then(|x| x.player_id());
self.body.x_vel *= -1.0;
self.body.y_vel *= -1.0;
set_action = ActionResult::set_action(ItemAction::Fall);
}
_ => { }
Expand Down
50 changes: 32 additions & 18 deletions canon_collision/src/entity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ pub(crate) mod components;
pub(crate) mod item;
pub(crate) mod player;
pub(crate) mod projectile;
pub(crate) mod toriel_fireball;

use player::{Player, RenderPlayer, MessagePlayer};
use projectile::{Projectile, ProjectileAction};
use toriel_fireball::TorielFireball;
use item::{Item, ItemAction, MessageItem};
use components::action_state::{ActionState, Hitlag};
use components::body::{Body};
Expand Down Expand Up @@ -37,6 +39,7 @@ pub enum EntityType {
Player (Player),
Projectile (Projectile),
Item (Item),
TorielFireball (TorielFireball),
}

#[derive(Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -73,6 +76,7 @@ impl Entity {
let face_left = angle > PI / 2.0 && angle < PI * 3.0 / 2.0;
!face_left
}
EntityType::TorielFireball (_) => true,
}
}

Expand All @@ -83,9 +87,10 @@ impl Entity {
pub fn public_bps_xy(&self, entities: &Entities, entity_defs: &KeyedContextVec<EntityDef>, surfaces: &[Surface]) -> (f32, f32) {
let action_frame = self.get_entity_frame(&entity_defs[self.state.entity_def_key.as_ref()]);
match &self.ty {
EntityType::Player (player) => player.body.public_bps_xy(entities, entity_defs, action_frame, surfaces, &self.state),
EntityType::Item (item) => item.body.public_bps_xy(entities, entity_defs, action_frame, surfaces, &self.state),
EntityType::Projectile (projectile) => (projectile.x, projectile.y)
EntityType::Player (player) => player.body.public_bps_xy(entities, entity_defs, action_frame, surfaces, &self.state),
EntityType::Item (item) => item.body.public_bps_xy(entities, entity_defs, action_frame, surfaces, &self.state),
EntityType::Projectile (projectile) => (projectile.x, projectile.y),
EntityType::TorielFireball (projectile) => (projectile.x, projectile.y),
}
}

Expand All @@ -95,15 +100,16 @@ impl Entity {
match &self.ty {
EntityType::Player (player) => player.body.public_bps_xyz(entities, entity_defs, action_frame, surfaces, &self.state),
EntityType::Item (item) => item.body.public_bps_xyz(entities, entity_defs, action_frame, surfaces, &self.state),
EntityType::Projectile (projectile) => (projectile.x, projectile.y, 0.0)
EntityType::Projectile (projectile) => (projectile.x, projectile.y, 0.0),
EntityType::TorielFireball (projectile) => (projectile.x, projectile.y, 0.0),
}
}

pub fn item_grab(&mut self, hit_key: EntityKey, hit_id: Option<usize>) {
let action_result = match &mut self.ty {
EntityType::Player (player) => player.item_grab(),
EntityType::Item (item) => item.grabbed(hit_key, hit_id),
EntityType::Projectile (_) => None
_ => None
};
self.process_action_result(action_result);
}
Expand All @@ -113,15 +119,17 @@ impl Entity {
EntityType::Player (player) => player.physics_step(context, &self.state, game_frame, goal),
EntityType::Item (item) => item.physics_step(context, &self.state),
EntityType::Projectile (_) => None,
EntityType::TorielFireball (_) => None,
};
self.process_action_result(action_result);
}

pub fn step_collision(&mut self, context: &mut StepContext, col_results: &[CollisionResult]) {
let action_result = match &mut self.ty {
EntityType::Player (player) => player.step_collision(context, &self.state, col_results),
EntityType::Item (item) => item.step_collision(col_results),
EntityType::Projectile (projectile) => projectile.step_collision(col_results),
EntityType::Player (player) => player.step_collision(context, &self.state, col_results),
EntityType::Item (item) => item.step_collision(context, &self.state, col_results),
EntityType::Projectile (projectile) => projectile.step_collision(col_results),
EntityType::TorielFireball (projectile) => projectile.step_collision(col_results),
};
self.process_action_result(action_result);
for col_result in col_results {
Expand Down Expand Up @@ -187,9 +195,10 @@ impl Entity {
}

match &mut self.ty {
EntityType::Player (player) => player.action_step(context, &self.state),
EntityType::Item (item) => item.action_step(context, &self.state),
EntityType::Projectile (projectile) => projectile.action_step(context, &self.state),
EntityType::Player (player) => player.action_step(context, &self.state),
EntityType::Item (item) => item.action_step(context, &self.state),
EntityType::Projectile (projectile) => projectile.action_step(context, &self.state),
EntityType::TorielFireball (projectile) => projectile.action_step(context, &self.state),
}
}

Expand All @@ -215,6 +224,7 @@ impl Entity {
EntityType::Player (player) => player.body.angle(entity_frame, surfaces),
EntityType::Item (item) => item.body.angle(entity_frame, surfaces),
EntityType::Projectile (projectile) => projectile.angle,
EntityType::TorielFireball (_) => 0.0,
}
} else {
0.0
Expand Down Expand Up @@ -272,6 +282,7 @@ impl Entity {
EntityType::Player (player) => Some(player.id),
EntityType::Item (item) => item.owner_id,
EntityType::Projectile (projectile) => projectile.owner_id,
EntityType::TorielFireball (projectile) => projectile.owner_id,
}
}

Expand All @@ -298,22 +309,23 @@ impl Entity {
EntityType::Player (player) => player.debug_print(entities, &self.state, player_input.unwrap(), debug, i),
EntityType::Item (item) => item.debug_print(entities, &self.state, debug, i),
EntityType::Projectile (projectile) => projectile.debug_print(entities, &self.state, debug, i),
EntityType::TorielFireball (projectile) => projectile.debug_print(entities, &self.state, debug, i),
}
}

pub fn body(&self) -> Option<&Body> {
match &self.ty {
EntityType::Player (player) => Some(&player.body),
EntityType::Item (item) => Some(&item.body),
EntityType::Projectile (_) => None
EntityType::Item (item) => Some(&item.body),
_ => None
}
}

pub fn body_mut(&mut self) -> Option<&mut Body> {
match &mut self.ty {
EntityType::Player (player) => Some(&mut player.body),
EntityType::Item (item) => Some(&mut item.body),
EntityType::Projectile (_) => None
EntityType::Item (item) => Some(&mut item.body),
_ => None
}
}

Expand All @@ -322,6 +334,7 @@ impl Entity {
EntityType::Player (player) => player.team,
EntityType::Item (_) => 0,
EntityType::Projectile (_) => 0,
EntityType::TorielFireball (_) => 0,
}
}

Expand Down Expand Up @@ -354,9 +367,10 @@ impl Entity {
}

let render_type = match &self.ty {
EntityType::Player (player) => RenderEntityType::Player (player.render(entities, entity_defs, surfaces, &self.state)),
EntityType::Projectile (_) => RenderEntityType::Projectile,
EntityType::Item (_) => RenderEntityType::Item,
EntityType::Player (player) => RenderEntityType::Player (player.render(entities, entity_defs, surfaces, &self.state)),
EntityType::Projectile (_) => RenderEntityType::Projectile,
EntityType::TorielFireball (_) => RenderEntityType::Projectile,
EntityType::Item (_) => RenderEntityType::Item,
};

let visible = match &self.ty {
Expand Down
13 changes: 8 additions & 5 deletions canon_collision/src/entity/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::results::{RawPlayerResult, DeathRecord};
use crate::rules::{Goal, Rules};
use crate::entity::item::{Item, ItemAction, MessageItem};
use crate::entity::projectile::{Projectile, ProjectileAction};
use crate::entity::toriel_fireball::{TorielFireball, TorielFireballAction};
use crate::entity::{Entity, EntityType, StepContext, DebugEntity, VectorArrow, Entities, EntityKey, Message, MessageContents, ActionResult};
use crate::entity::components::body::{Body, Location, PhysicsResult};
use crate::entity::components::action_state::ActionState;
Expand Down Expand Up @@ -877,18 +878,20 @@ impl Player {
if state.frame == 5 {
let (x, y) = self.bps_xy(context, state);
context.new_entities.push(Entity {
ty: EntityType::Projectile(
Projectile {
ty: EntityType::TorielFireball(
TorielFireball {
owner_id: Some(self.id),
speed: 0.6,
angle: if self.body.face_right { 0.0 } else { PI },
face_right: self.body.face_right,
x: x + self.relative_f(10.0),
y: y + 10.0,
y_vel: 2.2,
x_sin_counter: 0.0,
x_sin_origin: 0.0,
}
),
state: ActionState::new(
"TorielFireball.cbor".to_string(),
ProjectileAction::Spawn
TorielFireballAction::Spawn
),
});
}
Expand Down
117 changes: 117 additions & 0 deletions canon_collision/src/entity/toriel_fireball.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use crate::collision::collision_box::CollisionResult;
use crate::entity::{DebugEntity, StepContext, EntityKey, ActionResult};
use crate::entity::components::action_state::ActionState;

use canon_collision_lib::entity_def::EntityDef;

use num_traits::FromPrimitive;
use treeflection::KeyedContextVec;

#[repr(u64)]
#[derive(Clone, PartialEq, Debug, ToPrimitive, FromPrimitive, EnumIter, IntoStaticStr, Serialize, Deserialize)]
pub enum TorielFireballAction {
Spawn,
Travel,
Hit,
}

#[derive(Clone, Serialize, Deserialize)]
pub struct TorielFireball {
// TODO: Probably need a body to handle collision with the stage, shouldnt be too bad though.
pub owner_id: Option<usize>,
pub face_right: bool,
pub x: f32,
pub y: f32,
pub y_vel: f32,
pub x_sin_counter: f32,
pub x_sin_origin: f32,
}

impl TorielFireball {
pub fn action_step(&mut self, context: &mut StepContext, state: &ActionState) -> Option<ActionResult> {
match TorielFireballAction::from_u64(state.action) {
Some(TorielFireballAction::Travel) => {
if self.y_vel < -0.2 {
self.x_sin_counter += 0.07;
self.x = self.x_sin_origin + self.relative_f(self.x_sin_counter.sin() * 6.0);
} else {
self.y_vel -= 0.08;
self.x += self.relative_f(1.5);
self.x_sin_origin = self.x;
}
self.y += self.y_vel;
}
_ => { }
}

let blast = &context.stage.blast;
if self.x < blast.left() || self.x > blast.right() || self.y < blast.bot() || self.y > blast.top() {
context.delete_self = true;
}

let action_frames = context.entity_def.actions[state.action as usize].frames.len() as i64;
if state.frame + 1 >= action_frames {
self.action_expired(context, state)
} else {
None
}
}

pub fn relative_f(&self, input: f32) -> f32 {
input * if self.face_right { 1.0 } else { -1.0 }
}

fn action_expired(&mut self, context: &mut StepContext, state: &ActionState) -> Option<ActionResult> {
ActionResult::set_action(match TorielFireballAction::from_u64(state.action) {
None => panic!("Custom defined action expirations have not been implemented"),

// Idle
Some(TorielFireballAction::Spawn) => TorielFireballAction::Travel,
Some(TorielFireballAction::Travel) => TorielFireballAction::Travel,
Some(TorielFireballAction::Hit) => {
context.delete_self = true;
TorielFireballAction::Hit
}
})
}

pub fn step_collision(&mut self, col_results: &[CollisionResult]) -> Option<ActionResult> {
let mut set_action = None;

for col_result in col_results {
match col_result {
&CollisionResult::Clang { .. } => {
set_action = ActionResult::set_action(TorielFireballAction::Hit);
}
&CollisionResult::HitAtk { .. } => {
set_action = ActionResult::set_action(TorielFireballAction::Hit);
}
&CollisionResult::HitShieldAtk { .. } => {
set_action = ActionResult::set_action(TorielFireballAction::Hit);
}
&CollisionResult::ReflectAtk { .. } => {
// TODO
set_action = ActionResult::set_action(TorielFireballAction::Hit);
}
&CollisionResult::AbsorbAtk { .. } => {
set_action = ActionResult::set_action(TorielFireballAction::Hit);
}
_ => { }
}
}
set_action
}

pub fn debug_print(&self, entities: &KeyedContextVec<EntityDef>, state: &ActionState, debug: &DebugEntity, index: EntityKey) -> Vec<String> {
let mut lines = vec!();
if debug.action {
lines.push(state.debug_string::<TorielFireballAction>(entities, index));
}
if debug.physics {
//lines.push(format!("Entity: {:?} location: {:?} angle: {:.5}",
//index, (self.x, self.y), self.angle));
}

lines
}
}

0 comments on commit a9981f4

Please sign in to comment.