Enemies examples

Started by xavius, June 14, 2014, 07:17:55 PM

Previous topic - Next topic
Hi everybody,

I want to share some enemies that I have created with you. Could be useful for your projects. All of theses enemies are compatibles with this script http://forum.solarus-games.org/index.php/topic,51.0.html made by Christopho to reset enemies positions when crossing a separator.

I will add enemies time to time as I go in learning lua.

Homing bat
Simply, it is a bat that stands and do nothing. If you come close enough, it will go at you in a straight line. I used the Ganon firebat graphics for this, I changed the graphic script though to make it more realistic.

fire_bat.dat modified script:
animation{
  name = "stopped",
  src_image = "enemies/fire_bat.png",
  directions = {
    { x = 160, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 16, num_frames = 1 },
    { x = 160, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 16, num_frames = 1 },
    { x = 160, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 16, num_frames = 1 },
    { x = 160, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 16, num_frames = 1 },
  },
}

animation{
  name = "walking",
  src_image = "enemies/fire_bat.png",
  frame_delay = 50,
  frame_to_loop_on = 2,
  directions = {
    { x = 96, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 16, num_frames = 4 },
    { x = 96, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 16, num_frames = 4 },
    { x = 96, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 16, num_frames = 4 },
    { x = 96, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 16, num_frames = 4 },
  },
}

animation{
  name = "hurt",
  src_image = "enemies/fire_bat.png",
  frame_delay = 50,
  frame_to_loop_on = 0,
  directions = {
    { x = 192, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 16, num_frames = 2 },
    { x = 192, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 16, num_frames = 2 },
    { x = 192, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 16, num_frames = 2 },
    { x = 192, y = 0, frame_width = 32, frame_height = 32, origin_x = 16, origin_y = 16, num_frames = 2 },
  },
}



homing bat script
local enemy = ...
local going_hero = false
local m

function enemy:on_created()
  self:set_life(1)
  self:set_damage(2)
  self:create_sprite("enemies/fire_bat")
 
  self:set_size(16, 8)
  self:set_origin(8, 0)
  self:set_obstacle_behavior("flying")
  m = sol.movement.create("target")
  m:set_ignore_obstacles(false)
  m:set_speed(0)
  m:start(self)
end


function enemy:on_restarted()
  local sprite = self:get_sprite()
  sprite:set_animation("stopped")
  m:set_speed(0)
  going_hero = false

  self:go_random()
  self:check_hero()
end

function enemy:check_hero()
  local hero = self:get_map():get_entity("hero")
  local _, _, layer = self:get_position()
  local _, _, hero_layer = hero:get_position()
  local near_hero = layer == hero_layer
    and self:get_distance(hero) < 150

  if near_hero and not going_hero then
    self:go_hero()
sol.audio.play_sound("bat")

  elseif not near_hero and going_hero then
    self:go_random()
  end
  sol.timer.stop_all(self)
  sol.timer.start(self, 100, function() self:check_hero() end)
end

function enemy:go_random()
  going_hero = false
  local sprite = self:get_sprite()
  sprite:set_animation("stopped")
  m:set_speed(0)
end

function enemy:go_hero()
  going_hero = true
  local sprite = self:get_sprite()
  sprite:set_animation("walking")
  m:set_speed(88)
end





June 14, 2014, 07:34:46 PM #1 Last Edit: June 15, 2014, 12:40:16 AM by xavius
Guruguru bar

This is simply a reproduction of this ennemy: http://zeldawiki.org/Guruguru_Bar

I made two version, one clockwise and the other counter clockwise. Theses two enemies do not have graphics, they are simply the center of the firebar. The firebar itself is composed of another enemy.

I used the graphics of super mario world for the fireballs. See attached.

Here is the fireBall sprite script:
animation{
  name = "walking",
  src_image = "enemies/fireBall.png",
  frame_delay = 50,
  frame_to_loop_on = 0,
  directions = {
    { x = 0, y = 0, frame_width = 16, frame_height = 16, origin_x = 0, origin_y = 0, num_frames = 2 },
    { x = 0, y = 0, frame_width = 16, frame_height = 16, origin_x = 0, origin_y = 0, num_frames = 2 },
    { x = 0, y = 0, frame_width = 16, frame_height = 16, origin_x = 0, origin_y = 0, num_frames = 2 },
    { x = 0, y = 0, frame_width = 16, frame_height = 16, origin_x = 0, origin_y = 0, num_frames = 2 },
  },
}


The fireball ennemy:
local enemy = ...

function enemy:on_created()
  self:set_life(1)
  self:set_damage(2)
  self:create_sprite("fireBall")
  self:set_size(16, 16)
  self:set_origin(8, 8)
  self:set_invincible()
  self:set_obstacle_behavior("flying")
end

-- Circles around the enemy that created it
function enemy:go_circle(center_entity, rayon, notRev)
  local m = sol.movement.create("circle")
  m:set_center(center_entity, -8, -29)
  m:set_radius(rayon)
  m:set_angle_speed(88)
  m:set_ignore_obstacles(true)
  m:set_clockwise(notRev)
  m:start(self)
end


Clockwise firebar:
local enemy = ...
local son, son2, son3, son4

function enemy:on_created()

  self:set_life(1)
  self:set_damage(0)
  self:set_size(16, 16)
  self:set_origin(8, 8)
  self:set_invincible()
  self:set_obstacle_behavior("flying")
 
  son = self:create_enemy{
      name = son_name,
      breed = "fireBall",
      x = 0,
      y = 0,
      layer = 0,
    }
    son:go_circle(self, 16, true)
son:set_optimization_distance(0) -- We do not want the enemy to ever stop if player is too far,
-- take note this is consuming resourcces. Use disabled() function stop.

son2 = self:create_enemy{
      name = son_name,
      breed = "fireBall",
      x = 0,
      y = 0,
      layer = 0,
    }
    son2:go_circle(self, 32, true)
son2:set_optimization_distance(0)

son3 = self:create_enemy{
      name = son_name,
      breed = "fireBall",
      x = 0,
      y = 0,
      layer = 0,
    }
    son3:go_circle(self, 48, true)
son3:set_optimization_distance(0)

son4 = self:create_enemy{
      name = son_name,
      breed = "fireBall",
      x = 0,
      y = 0,
      layer = 0,
    }
    son4:go_circle(self, 64, true)
son4:set_optimization_distance(0)

son:set_enabled(true)
son2:set_enabled(true)
son3:set_enabled(true)
son4:set_enabled(true)
end

function enemy:on_restarted()
son:set_enabled(true)
son2:set_enabled(true)
son3:set_enabled(true)
son4:set_enabled(true)

son:go_circle(self, 16, true)
son:set_optimization_distance(0)
son2:go_circle(self, 32, true)
son2:set_optimization_distance(0)
son3:go_circle(self, 48, true)
son3:set_optimization_distance(0)
son4:go_circle(self, 64, true)
son4:set_optimization_distance(0)
end

function enemy:on_disabled()
son:set_enabled(false)
son2:set_enabled(false)
son3:set_enabled(false)
son4:set_enabled(false)
end


Counter clockwise firebar:
local enemy = ...
local son, son2, son3, son4

function enemy:on_created()

  self:set_life(1)
  self:set_damage(0)
  self:set_size(16, 16)
  self:set_origin(8, 8)
  self:set_invincible()
  self:set_obstacle_behavior("flying")
 
  son = self:create_enemy{
      name = son_name,
      breed = "fireBall",
      x = 0,
      y = 0,
      layer = 0,
    }
    son:go_circle(self, 16, false)
son:set_optimization_distance(0)

son2 = self:create_enemy{
      name = son_name,
      breed = "fireBall",
      x = 0,
      y = 0,
      layer = 0,
    }
    son2:go_circle(self, 32, false)
son2:set_optimization_distance(0)

son3 = self:create_enemy{
      name = son_name,
      breed = "fireBall",
      x = 0,
      y = 0,
      layer = 0,
    }
    son3:go_circle(self, 48, false)
son3:set_optimization_distance(0)

son4 = self:create_enemy{
      name = son_name,
      breed = "fireBall",
      x = 0,
      y = 0,
      layer = 0,
    }
    son4:go_circle(self, 64, false)
son4:set_optimization_distance(0)

son:set_enabled(true)
son2:set_enabled(true)
son3:set_enabled(true)
son4:set_enabled(true)
end

function enemy:on_restarted()
son:set_enabled(true)
son2:set_enabled(true)
son3:set_enabled(true)
son4:set_enabled(true)

son:go_circle(self, 16, false)
son:set_optimization_distance(0)
son2:go_circle(self, 32, false)
son2:set_optimization_distance(0)
son3:go_circle(self, 48, false)
son3:set_optimization_distance(0)
son4:go_circle(self, 64, false)
son4:set_optimization_distance(0)
end

function enemy:on_disabled()
son:set_enabled(false)
son2:set_enabled(false)
son3:set_enabled(false)
son4:set_enabled(false)
end




Nice scripts, I like them. I will share some of my enemies when they'll become enough debugged :p

Here is a new entity I have made.

This is simply a bumper. It has to be 16 x 16, I still have to work the code to make it flexible. It is pretty much the same as the bumpers in ALTTP except it is 16 x 16 instead of 32 x 32.


local entities = ...
local boingIsReady = true

--TODO: Make it compatible with separator manager script
function entities:on_created()
 
  -- Call a function every 22 milliseconds.
sol.timer.start(22, function()
if(boingIsReady == true) then
 
-- Get hero position
local hero_x, hero_y, hero_layer = self:get_map():get_entity("hero"):get_position()

-- When changed in engine, get hero width & height here
local hero_width = 16
local hero_height = 16

-- Get entity position
local ent_x, ent_y, ent_layer = self:get_position()
local ent_width, ent_height = self:get_size()

--TODO: change this line, I hate it, not clean at all
if( ( (ent_x - 12) < hero_x) and ( (ent_x + ent_width - 3) > hero_x) and ( (ent_y - 12) < hero_y) and ( (ent_y - 11 + ent_height) > hero_y) ) then
--self:get_map():get_entity("hero"):set_position(hero_x, hero_y + 1, hero_layer)

self:get_map():get_entity("hero"):freeze()

-- Get center point of entity and hero
local ent_center_x = ent_x + (ent_width / 2)
local ent_center_y = ent_y + (ent_height / 2)

local hero_center_x = hero_x + (hero_width / 2)
local hero_center_y = hero_y + (hero_height / 2)

-- Get delta x and delta y
local delta_x =  hero_center_x - ent_center_x
local delta_y =  hero_center_y - ent_center_y

local angle = 0

--Check if value is 0 or else division by 0
if(delta_x == 0) then
if(delta_y <= 0) then
angle = math.pi / 2
else
angle = 3 * math.pi / 2
end
else
-- Get angle with arctan
angle = math.atan(delta_y / delta_x)

-- Check the side of the angle
if(ent_center_x < hero_center_x) then
-- reverse angle, for some weird reason, atan start it's angle at pi instead of 0... Correct me if I am wrong
angle = angle * -1
elseif(ent_center_x > hero_center_x) then
-- Substract from pi
angle = math.pi - angle
end
end

-- Set movement stuff
local m = sol.movement.create("straight")
m:set_speed(130)
m:set_max_distance(32)
m:get_ignore_obstacles(false)

-- Set movement angle
m:set_angle(angle)

-- Start movement
m:start(self:get_map():get_entity("hero"))

-- Boing!
sol.audio.play_sound("bounce")

-- Lock function
boingIsReady = false

sol.timer.start(300, function()

-- Check if hero is still freezed, if not, do nothing
if( self:get_map():get_entity("hero"):get_state() == "freezed") then
self:get_map():get_entity("hero"):unfreeze()
end

-- Unlock function
boingIsReady = true
end)
end --If position
end --if(boingIsReady == true)
return true
end) --main timer
end