move the enemies to different places
This commit is contained in:
parent
e061a1405a
commit
f0142c3ed2
|
|
@ -0,0 +1,479 @@
|
||||||
|
use crate::Player;
|
||||||
|
use fyrox::graph::SceneGraph;
|
||||||
|
use fyrox::{
|
||||||
|
core::{
|
||||||
|
algebra::{Point2, Vector2, Vector3},
|
||||||
|
impl_component_provider,
|
||||||
|
pool::Handle,
|
||||||
|
reflect::prelude::*,
|
||||||
|
uuid_provider,
|
||||||
|
visitor::prelude::*,
|
||||||
|
},
|
||||||
|
scene::{
|
||||||
|
animation::spritesheet::SpriteSheetAnimation,
|
||||||
|
collider::{BitMask, InteractionGroups},
|
||||||
|
dim2::{
|
||||||
|
physics::{Intersection, RayCastOptions},
|
||||||
|
rectangle::Rectangle,
|
||||||
|
rigidbody::RigidBody,
|
||||||
|
},
|
||||||
|
graph::Graph,
|
||||||
|
node::Node,
|
||||||
|
},
|
||||||
|
script::{ScriptContext, ScriptTrait},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_component_provider!(Archer,);
|
||||||
|
uuid_provider!(Archer = "a5671d19-9f1a-4286-8486-add4ebaadaec");
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, Copy)]
|
||||||
|
enum Animations {
|
||||||
|
#[default]
|
||||||
|
Idle = 0,
|
||||||
|
Run = 1,
|
||||||
|
Fight = 2,
|
||||||
|
Dead = 3,
|
||||||
|
Block = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
const DISTANCE_TO_FIGHT: f32 = 0.5;
|
||||||
|
const DISTANCE_TO_VIEW: f32 = 5.0;
|
||||||
|
const END_MAP_LEFT: f32 = -30.0;
|
||||||
|
const END_MAP_RIGHT: f32 = 30.0;
|
||||||
|
const SPEED: f32 = 3.1;
|
||||||
|
|
||||||
|
#[derive(Visit, Reflect, Debug, Clone, Default)]
|
||||||
|
pub struct Archer {
|
||||||
|
// pub sprite: Handle<Node>,
|
||||||
|
move_left: bool,
|
||||||
|
move_right: bool,
|
||||||
|
jump: bool,
|
||||||
|
pub animations: Vec<SpriteSheetAnimation>,
|
||||||
|
fight: bool,
|
||||||
|
win: bool,
|
||||||
|
dead: bool,
|
||||||
|
block: bool,
|
||||||
|
|
||||||
|
#[reflect(hidden)]
|
||||||
|
#[visit(skip)]
|
||||||
|
current_animation: Animations,
|
||||||
|
|
||||||
|
handle: Handle<Node>,
|
||||||
|
player_handle: Handle<Node>,
|
||||||
|
player_collider: Handle<Node>,
|
||||||
|
|
||||||
|
attack_damage: f32,
|
||||||
|
attack_timer: f32,
|
||||||
|
attack_speed: f32,
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
}
|
||||||
|
impl Archer {
|
||||||
|
fn init(&mut self) {
|
||||||
|
self.attack_damage = 100.0;
|
||||||
|
self.attack_speed = 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn round(&self, a: f32) -> i32 {
|
||||||
|
return a.round() as i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_damage(&mut self, _damage: &f32) {
|
||||||
|
if self.dead {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.block = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersections_box(&self, graph: &mut Graph) -> bool {
|
||||||
|
if self.dead {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let self_node = match graph.try_get_mut(self.handle) {
|
||||||
|
Some(node) => node,
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
let self_position = self_node.global_position();
|
||||||
|
|
||||||
|
// Cast a ray from *this* node in the direction of the player node
|
||||||
|
let mut buffer = Vec::<Intersection>::new();
|
||||||
|
|
||||||
|
graph.physics2d.cast_ray(
|
||||||
|
RayCastOptions {
|
||||||
|
ray_origin: Point2::new(self_position.x, self_position.y),
|
||||||
|
ray_direction: Vector2::new(0.0, 1.0),
|
||||||
|
max_len: 0.5,
|
||||||
|
groups: InteractionGroups::default(),
|
||||||
|
// Sort the results by distance
|
||||||
|
sort_results: true,
|
||||||
|
},
|
||||||
|
// Store the collisions in the vector
|
||||||
|
&mut buffer,
|
||||||
|
);
|
||||||
|
if buffer.len() == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for i in 0..buffer.len() {
|
||||||
|
if self.player_handle == buffer[i].collider {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if buffer[i].toi == 0.0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if self.round(buffer[i].position[0]) != self.round(self_position.x) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if self.round(buffer[i].position[1]) == self.round(self_position.y) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersections_player(&self, graph: &mut Graph, max_len: f32) -> Option<Vec<Intersection>> {
|
||||||
|
if self.dead {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// Get *this* node instance
|
||||||
|
let self_node = match graph.try_get_mut(self.handle) {
|
||||||
|
Some(node) => node,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
let self_position = self_node.global_position();
|
||||||
|
|
||||||
|
// Get the player node
|
||||||
|
let player_node = match graph.try_get_mut(self.player_handle) {
|
||||||
|
Some(node) => node,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the current position of *this* node and the player node
|
||||||
|
let player_position = player_node.global_position();
|
||||||
|
|
||||||
|
// Calculate the direction vector from *this* node to the player node
|
||||||
|
let direction = player_position - self_position;
|
||||||
|
|
||||||
|
// Cast a ray from *this* node in the direction of the player node
|
||||||
|
let mut buffer = Vec::<Intersection>::new();
|
||||||
|
|
||||||
|
graph.physics2d.cast_ray(
|
||||||
|
RayCastOptions {
|
||||||
|
ray_origin: Point2::new(self_position.x, self_position.y),
|
||||||
|
ray_direction: Vector2::new(direction.x, direction.y),
|
||||||
|
max_len: max_len,
|
||||||
|
groups: InteractionGroups::new(
|
||||||
|
// Only collide with the player
|
||||||
|
BitMask(0b1000_0000_0000_0000_0000_0000_0000_0000),
|
||||||
|
BitMask(0b0111_1111_1111_1111_1111_1111_1111_1111),
|
||||||
|
),
|
||||||
|
// groups: InteractionGroups::default(),
|
||||||
|
// Sort the results by distance
|
||||||
|
sort_results: true,
|
||||||
|
},
|
||||||
|
// Store the collisions in the vector
|
||||||
|
&mut buffer,
|
||||||
|
);
|
||||||
|
if buffer.len() == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attack_player(&mut self, ctx: &mut ScriptContext) {
|
||||||
|
if self.win {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if !self.fight {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let player_script = ctx
|
||||||
|
.scene
|
||||||
|
.graph
|
||||||
|
.try_get_script_of_mut::<Player>(self.player_handle)
|
||||||
|
.unwrap();
|
||||||
|
if player_script.get_health() <= 0.0 {
|
||||||
|
self.fight = false;
|
||||||
|
self.block = false;
|
||||||
|
self.win = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.block = false;
|
||||||
|
player_script.take_damage(&self.attack_damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_player_position(&self, context: &mut ScriptContext) -> Vector3<f32> {
|
||||||
|
let player_binding = context.scene.graph.try_get_mut(self.player_handle).unwrap();
|
||||||
|
let player_rigid_body = player_binding.cast::<RigidBody>();
|
||||||
|
let player_rigid_data = match player_rigid_body {
|
||||||
|
Some(rigid_body) => rigid_body,
|
||||||
|
None => panic!("wrong player position"),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Vector3::new(
|
||||||
|
player_rigid_data.local_transform().position().x,
|
||||||
|
player_rigid_data.local_transform().position().y,
|
||||||
|
player_rigid_data.local_transform().position().z,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn distance_to_player(&self, context: &mut ScriptContext) -> f32 {
|
||||||
|
let player_position = self.get_player_position(context);
|
||||||
|
|
||||||
|
let enemy_binding = context.scene.graph.try_get_mut(context.handle).unwrap();
|
||||||
|
let enemy_rigid_body = enemy_binding.cast::<RigidBody>();
|
||||||
|
let enemy_rigid_data = match enemy_rigid_body {
|
||||||
|
Some(rigid_data) => rigid_data,
|
||||||
|
None => return 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: if player is places abroad maps - stop activity
|
||||||
|
// if player_position.x <= END_MAP_LEFT || player_position.x >= END_MAP_RIGHT {
|
||||||
|
// return 100.0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
let enemy_position = enemy_rigid_data.local_transform().position();
|
||||||
|
if player_position.y > enemy_position.y {
|
||||||
|
return DISTANCE_TO_VIEW * 2.0;
|
||||||
|
}
|
||||||
|
return player_position.x - enemy_position.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_speed(&self, context: &mut ScriptContext) -> f32 {
|
||||||
|
if self.dead {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
if self.win {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
let collaider = self.intersections_player(&mut context.scene.graph, DISTANCE_TO_VIEW);
|
||||||
|
let mut see_player: bool = false;
|
||||||
|
if let Some(collaider_data) = collaider {
|
||||||
|
for i in 0..collaider_data.len() {
|
||||||
|
if collaider_data[i].toi == 0.0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if collaider_data[i].collider == self.player_collider {
|
||||||
|
see_player = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !see_player {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let player_position = self.get_player_position(context);
|
||||||
|
let enemy_rigid_body = context.scene.graph[context.handle]
|
||||||
|
.cast_mut::<RigidBody>()
|
||||||
|
.unwrap();
|
||||||
|
if enemy_rigid_body.global_position().x <= END_MAP_LEFT {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
if enemy_rigid_body.global_position().x >= END_MAP_RIGHT {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
let mut dif_x = player_position.x - enemy_rigid_body.global_position().x;
|
||||||
|
if enemy_rigid_body.global_position().x > player_position.x {
|
||||||
|
dif_x = player_position.x - enemy_rigid_body.global_position().x;
|
||||||
|
}
|
||||||
|
if dif_x < 0.0 {
|
||||||
|
dif_x *= -1.0;
|
||||||
|
}
|
||||||
|
if player_position.y > enemy_rigid_body.global_position().y && dif_x < 1.0 {
|
||||||
|
if player_position.x > enemy_rigid_body.global_position().x {
|
||||||
|
return SPEED * -1.0;
|
||||||
|
}
|
||||||
|
if player_position.x < enemy_rigid_body.global_position().x {
|
||||||
|
return SPEED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if enemy_rigid_body.global_position().x < END_MAP_LEFT + 3.0 {
|
||||||
|
return SPEED / 2.0;
|
||||||
|
}
|
||||||
|
if enemy_rigid_body.global_position().x > END_MAP_RIGHT - 3.0 {
|
||||||
|
return SPEED / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let distance = self.distance_to_player(context);
|
||||||
|
if distance > DISTANCE_TO_VIEW {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if distance > DISTANCE_TO_FIGHT {
|
||||||
|
return SPEED;
|
||||||
|
}
|
||||||
|
if distance < DISTANCE_TO_FIGHT * -1.0 {
|
||||||
|
return SPEED * -1.0;
|
||||||
|
}
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_orientation(&self, context: &mut ScriptContext) {
|
||||||
|
let x_speed = self.get_speed(context);
|
||||||
|
if x_speed == 0.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let sprite = context.scene.graph.try_get_mut(context.handle);
|
||||||
|
match sprite {
|
||||||
|
Some(sprite_data) => {
|
||||||
|
// It is always a good practice to check whether the handles are valid, at this point we don't know
|
||||||
|
// for sure what's the value of the `sprite` field. It can be unassigned and the following code won't
|
||||||
|
// execute. A simple `context.scene.graph[self.sprite]` would just panicked in this case.
|
||||||
|
let local_transform: &mut fyrox::scene::transform::Transform =
|
||||||
|
sprite_data.local_transform_mut();
|
||||||
|
let current_scale = **local_transform.scale();
|
||||||
|
local_transform.set_scale(Vector3::new(
|
||||||
|
// Just change X scaling to mirror player's sprite.
|
||||||
|
current_scale.x.copysign(-x_speed),
|
||||||
|
current_scale.y,
|
||||||
|
current_scale.z,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_do(&mut self, context: &mut ScriptContext) {
|
||||||
|
let x_speed = self.get_speed(context);
|
||||||
|
if x_speed > 0.0 {
|
||||||
|
self.block = false;
|
||||||
|
}
|
||||||
|
let enemy_rigid_body = context.scene.graph[context.handle].cast_mut::<RigidBody>();
|
||||||
|
if let Some(enemy_rigid_data) = enemy_rigid_body {
|
||||||
|
enemy_rigid_data.set_lin_vel(Vector2::new(x_speed, -1.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn animate_choose(&mut self, context: &mut ScriptContext) {
|
||||||
|
self.current_animation = Animations::Idle;
|
||||||
|
if self.win {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.block {
|
||||||
|
self.current_animation = Animations::Block;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.dead {
|
||||||
|
self.current_animation = Animations::Dead;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.get_speed(context) != 0.0 {
|
||||||
|
self.current_animation = Animations::Run;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.fight {
|
||||||
|
self.current_animation = Animations::Fight;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_fight(&mut self, context: &mut ScriptContext) {
|
||||||
|
if self.win {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.dead {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.block {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let distance = self.distance_to_player(context);
|
||||||
|
self.fight = distance < DISTANCE_TO_FIGHT && distance > -1.0 * DISTANCE_TO_FIGHT;
|
||||||
|
if !self.fight {
|
||||||
|
self.attack_timer = 0.0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.attack_timer += context.dt;
|
||||||
|
if self.attack_timer >= self.attack_speed {
|
||||||
|
self.attack_player(context);
|
||||||
|
self.attack_timer = 0.0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.fight = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn animation_do(&mut self, context: &mut ScriptContext) {
|
||||||
|
self.animate_choose(context);
|
||||||
|
let cur_anim = self.current_animation as usize;
|
||||||
|
let current_animation = self.animations.get_mut(cur_anim);
|
||||||
|
match current_animation {
|
||||||
|
Some(animation_data) => {
|
||||||
|
{
|
||||||
|
let graph_ctx = context.scene.graph.begin_multi_borrow();
|
||||||
|
let enemy_rigid_data = match graph_ctx.try_get(context.handle) {
|
||||||
|
Ok(rigid_body) => rigid_body,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
for child in enemy_rigid_data.children().iter() {
|
||||||
|
if let Ok(mut enemy) = graph_ctx.try_get_mut(*child) {
|
||||||
|
if !enemy.is_rectangle() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let sprite: &mut Rectangle = enemy.cast_mut::<Rectangle>().unwrap();
|
||||||
|
animation_data.update(context.dt);
|
||||||
|
sprite
|
||||||
|
.material()
|
||||||
|
.data_ref()
|
||||||
|
.set_texture(&"diffuseTexture".into(), animation_data.texture())
|
||||||
|
.unwrap();
|
||||||
|
sprite.set_uv_rect(
|
||||||
|
animation_data.current_frame_uv_rect().unwrap_or_default(),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
animation_data.update(context.dt);
|
||||||
|
if let Some(sprite) = context
|
||||||
|
.scene
|
||||||
|
.graph
|
||||||
|
.try_get_mut(context.handle)
|
||||||
|
.and_then(|n| n.cast_mut::<Rectangle>())
|
||||||
|
{
|
||||||
|
sprite
|
||||||
|
.material()
|
||||||
|
.data_ref()
|
||||||
|
.set_texture(&"diffuseTexture".into(), animation_data.texture())
|
||||||
|
.unwrap();
|
||||||
|
sprite.set_uv_rect(animation_data.current_frame_uv_rect().unwrap_or_default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ScriptTrait for Archer {
|
||||||
|
fn on_init(&mut self, context: &mut ScriptContext) {
|
||||||
|
self.init();
|
||||||
|
// Store reference to *this* instance of the enemy node
|
||||||
|
self.handle = context.handle;
|
||||||
|
|
||||||
|
// Find the Player node
|
||||||
|
match context.scene.graph.find_by_name_from_root("Player") {
|
||||||
|
// (Handle<Node>, Node)
|
||||||
|
Some(handle) => {
|
||||||
|
// If found, store the handle
|
||||||
|
self.player_handle = handle.0;
|
||||||
|
|
||||||
|
// Find and store the Player's collider node handle
|
||||||
|
for child in handle.1.children().iter() {
|
||||||
|
self.player_collider = *child;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_update(&mut self, context: &mut ScriptContext) {
|
||||||
|
if self.intersections_box(&mut context.scene.graph) {
|
||||||
|
self.dead = true
|
||||||
|
}
|
||||||
|
self.set_fight(context);
|
||||||
|
self.change_orientation(context);
|
||||||
|
self.animation_do(context);
|
||||||
|
self.move_do(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod enemy;
|
||||||
|
pub mod spawn;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::Enemy;
|
use crate::Archer;
|
||||||
use fyrox::{
|
use fyrox::{
|
||||||
asset::manager::ResourceManager,
|
asset::manager::ResourceManager,
|
||||||
core::{
|
core::{
|
||||||
|
|
@ -25,20 +25,20 @@ use fyrox::{
|
||||||
rigidbody::RigidBodyType,
|
rigidbody::RigidBodyType,
|
||||||
transform::TransformBuilder,
|
transform::TransformBuilder,
|
||||||
},
|
},
|
||||||
script::{Script, ScriptContext, ScriptTrait},
|
script::{ScriptContext, ScriptTrait},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl_component_provider!(EnemySpawn,);
|
impl_component_provider!(ArcherSpawn,);
|
||||||
uuid_provider!(EnemySpawn = "b5671d19-9f1a-4286-8486-add4ebaadaec");
|
uuid_provider!(ArcherSpawn = "b5671d19-9f1a-4286-8486-add4ebaadaec");
|
||||||
#[derive(Visit, Reflect, Debug, Clone, Default)]
|
#[derive(Visit, Reflect, Debug, Clone, Default)]
|
||||||
pub struct EnemySpawn {
|
pub struct ArcherSpawn {
|
||||||
x: f32,
|
x: f32,
|
||||||
y: f32,
|
y: f32,
|
||||||
enemy: Enemy,
|
enemy: Archer,
|
||||||
}
|
}
|
||||||
impl EnemySpawn {
|
impl ArcherSpawn {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
return EnemySpawn::default();
|
return ArcherSpawn::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -144,7 +144,7 @@ impl EnemySpawn {
|
||||||
|
|
||||||
pub fn spawn_enemy(&self, graph: &mut Graph, resource_manager: &ResourceManager, x: f32) {
|
pub fn spawn_enemy(&self, graph: &mut Graph, resource_manager: &ResourceManager, x: f32) {
|
||||||
// TODO: add with_build
|
// TODO: add with_build
|
||||||
let mut enemy = Enemy::default();
|
let mut enemy = Archer::default();
|
||||||
enemy.x = x;
|
enemy.x = x;
|
||||||
enemy.y = -3.0;
|
enemy.y = -3.0;
|
||||||
let x = enemy.x;
|
let x = enemy.x;
|
||||||
|
|
@ -207,7 +207,7 @@ impl EnemySpawn {
|
||||||
.build(graph);
|
.build(graph);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ScriptTrait for EnemySpawn {
|
impl ScriptTrait for ArcherSpawn {
|
||||||
fn on_init(&mut self, context: &mut ScriptContext) {
|
fn on_init(&mut self, context: &mut ScriptContext) {
|
||||||
let resource_manager: &ResourceManager = &context.resource_manager;
|
let resource_manager: &ResourceManager = &context.resource_manager;
|
||||||
self.spawn_enemy(&mut context.scene.graph, resource_manager, 0.0);
|
self.spawn_enemy(&mut context.scene.graph, resource_manager, 0.0);
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod swordsman;
|
||||||
|
pub mod archer;
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod enemy;
|
||||||
|
pub mod spawn;
|
||||||
|
|
@ -0,0 +1,216 @@
|
||||||
|
use crate::Swordman;
|
||||||
|
use fyrox::{
|
||||||
|
asset::manager::ResourceManager,
|
||||||
|
core::{
|
||||||
|
algebra::{Vector2, Vector3},
|
||||||
|
impl_component_provider,
|
||||||
|
math::Rect,
|
||||||
|
reflect::prelude::*,
|
||||||
|
sstorage::ImmutableString,
|
||||||
|
uuid_provider,
|
||||||
|
visitor::prelude::*,
|
||||||
|
},
|
||||||
|
generic_animation::spritesheet::{ImageParameters, SpriteSheetAnimation},
|
||||||
|
material::{shader::SamplerFallback, Material, MaterialResource, PropertyValue},
|
||||||
|
resource::texture::Texture,
|
||||||
|
scene::{
|
||||||
|
base::BaseBuilder,
|
||||||
|
collider::InteractionGroups,
|
||||||
|
dim2::{
|
||||||
|
collider::{CapsuleShape, ColliderBuilder, ColliderShape},
|
||||||
|
rectangle::RectangleBuilder,
|
||||||
|
rigidbody::RigidBodyBuilder,
|
||||||
|
},
|
||||||
|
graph::Graph,
|
||||||
|
rigidbody::RigidBodyType,
|
||||||
|
transform::TransformBuilder,
|
||||||
|
},
|
||||||
|
script::{ScriptContext, ScriptTrait},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl_component_provider!(SwordmanSpawn,);
|
||||||
|
uuid_provider!(SwordmanSpawn = "b5671d19-9f1a-4286-8486-add4ebaadaec");
|
||||||
|
#[derive(Visit, Reflect, Debug, Clone, Default)]
|
||||||
|
pub struct SwordmanSpawn {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
enemy: Swordman,
|
||||||
|
}
|
||||||
|
impl SwordmanSpawn {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
return SwordmanSpawn::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn block_anmation(&self, resource_manager: &ResourceManager) -> SpriteSheetAnimation<fyrox::asset::Resource<Texture>> {
|
||||||
|
let idle = resource_manager.request::<Texture>(
|
||||||
|
"assets/data/characters/skeleton/Skeleton_Warrior/Protect.png".to_owned(),
|
||||||
|
);
|
||||||
|
let mut idle_animation = SpriteSheetAnimation::new_from_image_parameters(ImageParameters {
|
||||||
|
width: 128,
|
||||||
|
height: 128,
|
||||||
|
frame_width: 128,
|
||||||
|
frame_height: 128,
|
||||||
|
first_frame: 0,
|
||||||
|
last_frame: 1,
|
||||||
|
column_major: false,
|
||||||
|
});
|
||||||
|
idle_animation.set_texture(Some(idle));
|
||||||
|
idle_animation.set_looping(false);
|
||||||
|
idle_animation.set_speed(20.);
|
||||||
|
idle_animation.play();
|
||||||
|
return idle_animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attack_anmation(&self, resource_manager: &ResourceManager) -> SpriteSheetAnimation<fyrox::asset::Resource<Texture>> {
|
||||||
|
let idle = resource_manager.request::<Texture>(
|
||||||
|
"assets/data/characters/skeleton/Skeleton_Warrior/Attack_3.png".to_owned(),
|
||||||
|
);
|
||||||
|
let mut idle_animation = SpriteSheetAnimation::new_from_image_parameters(ImageParameters {
|
||||||
|
width: 512,
|
||||||
|
height: 128,
|
||||||
|
frame_width: 128,
|
||||||
|
frame_height: 128,
|
||||||
|
first_frame: 0,
|
||||||
|
last_frame: 6,
|
||||||
|
column_major: false,
|
||||||
|
});
|
||||||
|
idle_animation.set_texture(Some(idle));
|
||||||
|
idle_animation.set_looping(true);
|
||||||
|
idle_animation.set_speed(20.);
|
||||||
|
idle_animation.play();
|
||||||
|
return idle_animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_anmation(&self, resource_manager: &ResourceManager) -> SpriteSheetAnimation<fyrox::asset::Resource<Texture>> {
|
||||||
|
let idle = resource_manager.request::<Texture>(
|
||||||
|
"assets/data/characters/skeleton/Skeleton_Warrior/Run.png".to_owned(),
|
||||||
|
);
|
||||||
|
let mut idle_animation = SpriteSheetAnimation::new_from_image_parameters(ImageParameters {
|
||||||
|
width: 1024,
|
||||||
|
height: 128,
|
||||||
|
frame_width: 128,
|
||||||
|
frame_height: 128,
|
||||||
|
first_frame: 0,
|
||||||
|
last_frame: 8,
|
||||||
|
column_major: false,
|
||||||
|
});
|
||||||
|
idle_animation.set_texture(Some(idle));
|
||||||
|
idle_animation.set_looping(true);
|
||||||
|
idle_animation.set_speed(10.);
|
||||||
|
idle_animation.play();
|
||||||
|
return idle_animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn die_anmation(&self, resource_manager: &ResourceManager) -> SpriteSheetAnimation<fyrox::asset::Resource<Texture>> {
|
||||||
|
let idle = resource_manager.request::<Texture>(
|
||||||
|
"assets/data/characters/skeleton/Skeleton_Warrior/Dead.png".to_owned(),
|
||||||
|
);
|
||||||
|
let mut idle_animation = SpriteSheetAnimation::new_from_image_parameters(ImageParameters {
|
||||||
|
width: 512,
|
||||||
|
height: 128,
|
||||||
|
frame_width: 128,
|
||||||
|
frame_height: 128,
|
||||||
|
first_frame: 0,
|
||||||
|
last_frame: 4,
|
||||||
|
column_major: false,
|
||||||
|
});
|
||||||
|
idle_animation.set_texture(Some(idle));
|
||||||
|
idle_animation.set_looping(false);
|
||||||
|
idle_animation.set_speed(10.);
|
||||||
|
idle_animation.play();
|
||||||
|
return idle_animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn idle_anmation(&self, resource_manager: &ResourceManager) -> SpriteSheetAnimation<fyrox::asset::Resource<Texture>> {
|
||||||
|
let idle = resource_manager.request::<Texture>(
|
||||||
|
"assets/data/characters/skeleton/Skeleton_Warrior/Idle.png".to_owned(),
|
||||||
|
);
|
||||||
|
let mut idle_animation = SpriteSheetAnimation::new_from_image_parameters(ImageParameters {
|
||||||
|
width: 896,
|
||||||
|
height: 128,
|
||||||
|
frame_width: 128,
|
||||||
|
frame_height: 128,
|
||||||
|
first_frame: 0,
|
||||||
|
last_frame: 7,
|
||||||
|
column_major: false,
|
||||||
|
});
|
||||||
|
idle_animation.set_texture(Some(idle));
|
||||||
|
idle_animation.set_looping(true);
|
||||||
|
idle_animation.set_speed(10.);
|
||||||
|
idle_animation.play();
|
||||||
|
return idle_animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_enemy(&self, graph: &mut Graph, resource_manager: &ResourceManager, x: f32) {
|
||||||
|
// TODO: add with_build
|
||||||
|
let mut enemy = Swordman::default();
|
||||||
|
enemy.x = x;
|
||||||
|
enemy.y = -3.0;
|
||||||
|
let x = enemy.x;
|
||||||
|
let y = enemy.y;
|
||||||
|
let mut material = Material::standard_2d();
|
||||||
|
enemy.animations = vec![
|
||||||
|
self.idle_anmation(resource_manager),
|
||||||
|
self.run_anmation(resource_manager),
|
||||||
|
self.attack_anmation(resource_manager),
|
||||||
|
self.die_anmation(resource_manager),
|
||||||
|
self.block_anmation(resource_manager),
|
||||||
|
];
|
||||||
|
material
|
||||||
|
.set_property(
|
||||||
|
&ImmutableString::new("diffuseTexture"),
|
||||||
|
PropertyValue::Sampler {
|
||||||
|
value: None,
|
||||||
|
fallback: SamplerFallback::Normal,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let shape = ColliderShape::Capsule(CapsuleShape {
|
||||||
|
begin: Vector2::new(0.0, -0.80),
|
||||||
|
end: Vector2::new(0.0, -0.35),
|
||||||
|
radius: 0.2,
|
||||||
|
});
|
||||||
|
let rb_transform = TransformBuilder::new()
|
||||||
|
.with_local_position(Vector3::new(x, y, 0.0))
|
||||||
|
.with_local_scale(Vector3::new(2.0, 2.0, 1.0))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
RigidBodyBuilder::new(
|
||||||
|
BaseBuilder::new()
|
||||||
|
.with_children(&[
|
||||||
|
// Collider to prevent player from moving past boundary
|
||||||
|
RectangleBuilder::new(BaseBuilder::new())
|
||||||
|
.with_material(MaterialResource::new_ok(Default::default(), material))
|
||||||
|
// Sprite is located in top left corner of sprite sheet
|
||||||
|
.with_uv_rect(Rect::new(0.0, 0.3, 0.13, 0.8))
|
||||||
|
.build(graph),
|
||||||
|
ColliderBuilder::new(BaseBuilder::new())
|
||||||
|
.with_shape(shape)
|
||||||
|
.with_collision_groups(InteractionGroups::default())
|
||||||
|
.with_solver_groups(InteractionGroups::default())
|
||||||
|
.build(graph),
|
||||||
|
])
|
||||||
|
// Optional, set name of tile
|
||||||
|
.with_name(format!("Sceleton ({x}, {y})",))
|
||||||
|
// Set position of tile
|
||||||
|
.with_local_transform(rb_transform)
|
||||||
|
.with_script(enemy),
|
||||||
|
)
|
||||||
|
.with_mass(20.0)
|
||||||
|
// Turn off gravity for tile
|
||||||
|
.with_gravity_scale(1.)
|
||||||
|
.with_lin_damping(0.0)
|
||||||
|
// Set tile to be static and not rotate
|
||||||
|
.with_rotation_locked(true)
|
||||||
|
.with_body_type(RigidBodyType::Dynamic)
|
||||||
|
.build(graph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ScriptTrait for SwordmanSpawn {
|
||||||
|
fn on_init(&mut self, context: &mut ScriptContext) {
|
||||||
|
let resource_manager: &ResourceManager = &context.resource_manager;
|
||||||
|
self.spawn_enemy(&mut context.scene.graph, resource_manager, 0.0);
|
||||||
|
// self.enemy.on_init(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
//! Game project.
|
//! Game project.
|
||||||
|
use fyrox::graph::SceneGraph;
|
||||||
use fyrox::{
|
use fyrox::{
|
||||||
asset::manager::ResourceManager,
|
asset::manager::ResourceManager,
|
||||||
core::{log::Log, pool::Handle},
|
core::{log::Log, pool::Handle},
|
||||||
|
|
@ -11,18 +12,16 @@ use fyrox::{
|
||||||
UiNode, UserInterface,
|
UiNode, UserInterface,
|
||||||
},
|
},
|
||||||
plugin::{Plugin, PluginConstructor, PluginContext, PluginRegistrationContext},
|
plugin::{Plugin, PluginConstructor, PluginContext, PluginRegistrationContext},
|
||||||
scene::{graph::Graph, Scene,},
|
scene::{graph::Graph, Scene},
|
||||||
};
|
};
|
||||||
use fyrox::graph::SceneGraph;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
mod enemy;
|
mod enemies;
|
||||||
mod enemy_spawn;
|
|
||||||
mod map;
|
mod map;
|
||||||
mod msg;
|
mod msg;
|
||||||
mod player;
|
mod player;
|
||||||
|
|
||||||
use enemy::Enemy;
|
use enemies::swordsman::{enemy::Swordman, spawn::SwordmanSpawn};
|
||||||
use enemy_spawn::EnemySpawn;
|
use enemies::archer::{enemy::Archer, spawn::ArcherSpawn};
|
||||||
use map::build_map;
|
use map::build_map;
|
||||||
use msg::Message;
|
use msg::Message;
|
||||||
use player::Player;
|
use player::Player;
|
||||||
|
|
@ -33,7 +32,7 @@ impl PluginConstructor for GameConstructor {
|
||||||
fn register(&self, context: PluginRegistrationContext) {
|
fn register(&self, context: PluginRegistrationContext) {
|
||||||
// Register your scripts here.
|
// Register your scripts here.
|
||||||
let script_constructors = &context.serialization_context.script_constructors;
|
let script_constructors = &context.serialization_context.script_constructors;
|
||||||
script_constructors.add::<Enemy>("Enemy");
|
script_constructors.add::<Swordman>("Enemy");
|
||||||
script_constructors.add::<Player>("Player");
|
script_constructors.add::<Player>("Player");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,6 +46,7 @@ pub struct Game {
|
||||||
|
|
||||||
new_game: Handle<UiNode>,
|
new_game: Handle<UiNode>,
|
||||||
exit: Handle<UiNode>,
|
exit: Handle<UiNode>,
|
||||||
|
level: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
|
|
@ -56,7 +56,10 @@ impl Game {
|
||||||
|result, game: &mut Game, ctx| match result {
|
|result, game: &mut Game, ctx| match result {
|
||||||
Ok(menu) => {
|
Ok(menu) => {
|
||||||
*ctx.user_interface = menu;
|
*ctx.user_interface = menu;
|
||||||
(game.new_game, _) = ctx.user_interface.find_by_name_from_root("NewGame").unwrap();
|
(game.new_game, _) = ctx
|
||||||
|
.user_interface
|
||||||
|
.find_by_name_from_root("NewGame")
|
||||||
|
.unwrap();
|
||||||
(game.exit, _) = ctx.user_interface.find_by_name_from_root("Exit").unwrap();
|
(game.exit, _) = ctx.user_interface.find_by_name_from_root("Exit").unwrap();
|
||||||
}
|
}
|
||||||
Err(e) => Log::err(format!("Unable to load main menu! Reason: {:?}", e)),
|
Err(e) => Log::err(format!("Unable to load main menu! Reason: {:?}", e)),
|
||||||
|
|
@ -68,6 +71,7 @@ impl Game {
|
||||||
scene: Handle::NONE,
|
scene: Handle::NONE,
|
||||||
new_game: Handle::NONE,
|
new_game: Handle::NONE,
|
||||||
exit: Handle::NONE,
|
exit: Handle::NONE,
|
||||||
|
level: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,8 +117,7 @@ impl Plugin for Game {
|
||||||
MessageDirection::ToWidget,
|
MessageDirection::ToWidget,
|
||||||
false,
|
false,
|
||||||
));
|
));
|
||||||
ctx.async_scene_loader
|
ctx.async_scene_loader.request("data/scene.rgs");
|
||||||
.request("data/scene.rgs");
|
|
||||||
} else if message.destination() == self.exit {
|
} else if message.destination() == self.exit {
|
||||||
if let Some(window_target) = ctx.window_target {
|
if let Some(window_target) = ctx.window_target {
|
||||||
window_target.exit();
|
window_target.exit();
|
||||||
|
|
@ -148,6 +151,11 @@ impl Plugin for Game {
|
||||||
let graph: &mut Graph = &mut context.scenes[self.scene].graph;
|
let graph: &mut Graph = &mut context.scenes[self.scene].graph;
|
||||||
let resource_manager: &ResourceManager = &context.resource_manager;
|
let resource_manager: &ResourceManager = &context.resource_manager;
|
||||||
build_map(graph, resource_manager);
|
build_map(graph, resource_manager);
|
||||||
EnemySpawn::new().spawn_enemy(graph, resource_manager, -5.0);
|
if self.level == 1 {
|
||||||
|
SwordmanSpawn::new().spawn_enemy(graph, resource_manager, -5.0);
|
||||||
|
}
|
||||||
|
if self.level == 2 {
|
||||||
|
ArcherSpawn::new().spawn_enemy(graph, resource_manager, -5.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use crate::msg::Message;
|
use crate::msg::Message;
|
||||||
use crate::Enemy;
|
use crate::Swordman;
|
||||||
use fyrox::graph::BaseSceneGraph;
|
use fyrox::graph::BaseSceneGraph;
|
||||||
use fyrox::{
|
use fyrox::{
|
||||||
core::{
|
core::{
|
||||||
|
|
@ -52,6 +52,7 @@ pub struct Player {
|
||||||
start_fight_last: f32,
|
start_fight_last: f32,
|
||||||
prev_y_velosity: f32,
|
prev_y_velosity: f32,
|
||||||
damage: f32,
|
damage: f32,
|
||||||
|
damage: f32,
|
||||||
|
|
||||||
pub window_height: u32, // TODO: need change place
|
pub window_height: u32, // TODO: need change place
|
||||||
pub window_width: u32,
|
pub window_width: u32,
|
||||||
|
|
@ -366,9 +367,10 @@ impl Player {
|
||||||
let enemy_script = context
|
let enemy_script = context
|
||||||
.scene
|
.scene
|
||||||
.graph
|
.graph
|
||||||
.try_get_script_of_mut::<Enemy>(d)
|
.try_get_script_of_mut::<Swordman>(d);
|
||||||
.unwrap();
|
if let Some(enemy) = enemy_script {
|
||||||
enemy_script.take_damage(&self.damage);
|
enemy.take_damage(&self.damage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue