Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - Max

Pages: 1 [2]
16
Development / Moving a dynamically-created entity
« on: March 15, 2018, 12:38:18 am »
So I'm designing basically a Hinox enemy, who will throw bombs at you if you are within range. Everything is going great, and I just have a small problem that I'd like to know if I can fix a different way than I did.

Basically, I use map:create_bomb(), and then create a jump movement and "throw" the bomb toward the player that way. However, if I end up creating a new bomb before the old one explodes, the code "throws" the first bomb again instead of the newly created one, since the newly created bomb isn't called hinox_bomb, it's called hinox_bomb_2 since the first one is still around.

I got around this by just detonating the first bomb if it's still lying around before throwing a second one, which works well. But is there a better way to do this that anyone can think of?



The code for when the enemy throws bombs is this:

Code: (lua) [Select]
function enemy:shoot()
    --first, check if the hero is in the same region
  local map = enemy:get_map()
  local hero = map:get_hero()
  if not enemy:is_in_same_region(hero) then
  return true  -- Repeat the timer.
  end

  local sprite = enemy:get_sprite()
  local x, y, layer = enemy:get_position()
  local direction = sprite:get_direction()

  sprite:set_animation("shooting")
  enemy:stop_movement()

    --destroy an old bomb before creating a new one (mainly so we don't move the old bomb with our movement)
    if map:has_entity("hinox_bomb") == true then
      local bombx, bomby, bombl = map:get_entity("hinox_bomb"):get_position()
      map:create_explosion({x = bombx, y = bomby, layer = bombl, })
      sol.audio.play_sound("explosion")
      map:get_entity("hinox_bomb"):remove()
    end

    --now let's create a new bomb after we give the enemy a second to pull it out of his pocket
  sol.timer.start(enemy, 400, function()
      map:create_bomb({
        name = "hinox_bomb", x = x, y = y, layer = layer,
      })
    --and throw the new bomb toward the player
      local bomb_toss = sol.movement.create("jump")
      local dir_to_hero = self:get_direction8_to(hero)
      bomb_toss:set_direction8(dir_to_hero)
      bomb_toss:set_distance(dist_hero + 16)
      bomb_toss:set_speed(90)
      bomb_toss:start(map:get_entity("hinox_bomb"))
      sol.audio.play_sound("throw")
    sprite:set_animation("walking")

      --now the enemy can go back to what it was doing before it threw the bomb
      self:go_random()
      self:check_hero()

  end)
end


If anyone is interested in the whole code, I can post that for general use also if nobody's already made an enemy like this. It's based on the Solarus Team's scripts, and is actually pretty fun to battle because the best strategy is to pick up its bombs and throw them back. This could also be used for a "King Moblin" type enemy, which has appeared in a few Zelda games.

17
Development / Enemy Timers
« on: March 14, 2018, 02:52:46 am »
Hey, question. So timers associated with an enemy are destroyed when enemy:on_restarted() is called. However, enemy:on_restarted is called when the enemy is damaged, right? Therefore, it seems impossible to create a timer that sends an enemy through phases without you interrupting the phases whenever you hit the enemy.

For example, how would we have an enemy that becomes invulnerable after 10 seconds? You'd need to start that timer in enemy:on_restarted(), but that timer would be destroyed and restarted every time you damage the enemy.

Has anyone done anything like this in designing enemies?

18
Development / Enemy Obstacle Behavior: Swimming
« on: March 07, 2018, 07:11:26 pm »
Hey, so I was trying to make a zora kind of guy, and I set his behavior to swimming. Now he will swim through the ground with impunity. Does the swimming behavior allow enemies to walk on the ground also? Is there a behavior that keeps them in the water? Thanks!

19
Game art & music / Oceansheart Graphics
« on: March 06, 2018, 04:04:57 am »
Hey! I wanted to do something to help out the community. I like to think graphic art is one of my talents, and I've put in many many hours of work on tiles for the game I'm working on. I figure some of them might come in handy for others.

They're not necessarily compatible stylistically with Link to the Past graphics, because I taught myself pixel art looking at Minish Cap, haha, but at least the perspective is similar. I like to think these are a little more flexible in terms of topographical layout. Feel free to use these however you like, but please give me credit if you use them. It'd also be super cool if you let me know where my art goes, just because that's fun to track and see other people getting use out of my work : )


If you have any advice or feedback, I'm always looking to improve my talents and will welcome it.



20
Development / Enemies drowning animation?
« on: March 02, 2018, 10:14:06 pm »
Hey all.

So when you knock an enemy or throw a carried item into a hazard (water, pit, probably lava too), the engine recognizes this and will remove it and play an appropriate sound. However, it doesn't show any animation. I'm not sure if I just need to create one in the right location or what, but is there a default animation for items or enemies to fall into hazards?

I'm sure one could code a script that checks for enemies or items tossed into hazards, but I'm really just curious for now if that's something the engine can already do that I'm just missing resources for.

21
Your scripts / Leever-type enemy
« on: February 27, 2018, 04:45:24 pm »
So I've been learning how the solarus team does enemy scripts, and based on that system and their scripts, I've made one I think some people might find useful. It's enemy behavior modeled after the leevers from Zelda, but I've also found it useful for ghosts, and if you made some projectile addition, you could use it for a zora-type enemy too.

This one is made to follow the player if they're close enough to the enemy, but I've taken that part out for some more indifferent enemy types. One problem I've found with this script is that if you attack the enemy, it resets the timer for going underground. So if you keep hitting the enemy quickly, they won't have a chance to escape underground. I'm not 100% sure how to address that.


Code: (lua) [Select]
local behavior = {}

--This enemy is like Zelda's Leever. It moves randomly, and periodically will burrow below ground to later pop up. It is invulnerable when below ground. Special properties of this enemy type are time_underground, time_aboveground, and burrow_deviation. Time below/above ground are minimums, with the deviation being the random amount (in ms) to add to that. That keeps them from popping in and out in swarms if you have multiple. You could also use this for a ghost that phases in/out.
--Required sprites are walking, burrowing, and underground (which can be an empty graphic if you don't want they player to know where they are.
--You'll also need a sound called "burrow1" so they can make a noise and they go underground.

-- The properties parameter is a table.
-- All its values are optional except the sprite.

function behavior:create(enemy, properties)

  local going_hero = false
  local underground = false
 

  -- Set default properties.
  if properties.size_x == nil then
    properties.size_x = 16
  end
  if properties.size_y == nil then
    properties.size_y = 16
  end
  if properties.life == nil then
    properties.life = 2
  end
  if properties.damage == nil then
    properties.damage = 2
  end
  if properties.normal_speed == nil then
    properties.normal_speed = 32
  end
  if properties.faster_speed == nil then
    properties.faster_speed = 48
  end
  if properties.hurt_style == nil then
    properties.hurt_style = "normal"
  end
  if properties.pushed_when_hurt == nil then
    properties.pushed_when_hurt = true
  end
  if properties.push_hero_on_sword == nil then
    properties.push_hero_on_sword = false
  end
  if properties.ignore_obstacles == nil then
    properties.ignore_obstacles = false
  end
  if properties.detection_distance == nil then
    properties.detection_distance = 80
  end
  if properties.obstacle_behavior == nil then
    properties.obstacle_behavior = "normal"
  end
  if properties.movement_create == nil then
    properties.movement_create = function()
      local m = sol.movement.create("random_path")
      return m
    end
  end
  if properties.time_underground == nil then
    properties.time_underground = 2000
  end
  if properties.time_aboveground == nil then
    properties.time_aboveground = 3000
  end
  if properties.burrow_deviation == nil then
    properties.burrow_deviation = 6000
  end
  if properties.burrow_sound == nil then
    properties.burrow_sound = "burrow1"
  end
 

--create enemy properties
  function enemy:on_created()

    self:set_life(properties.life)
    self:set_damage(properties.damage)
    self:create_sprite(properties.sprite)
    self:set_hurt_style(properties.hurt_style)
    self:set_pushed_back_when_hurt(properties.pushed_when_hurt)
    self:set_push_hero_on_sword(properties.push_hero_on_sword)
    self:set_obstacle_behavior(properties.obstacle_behavior)
    self:set_size(properties.size_x, properties.size_y)
    self:set_origin(properties.size_x / 2, properties.size_y - 3)

  end


  function enemy:on_movement_changed(movement)

    local direction4 = movement:get_direction4()
    local sprite = self:get_sprite()
    sprite:set_direction(direction4)
  end


  function enemy:on_restarted()
    self:go_random()
    self:check_hero()
   
  end

 

  function enemy:burrow_down()
    sol.timer.stop_all(self)
    self:get_sprite():set_animation("burrowing")
    --play the sound if you're close enough
    local hero = self:get_map():get_entity("hero")
    local _, _, layer = self:get_position()
    local near_hero = self:get_distance(hero) < 140
    if near_hero then sol.audio.play_sound(properties.burrow_sound) end
    sol.timer.start(self, 800, function() self:go_underground() end)
  end

  function enemy:burrow_up()
    self:get_sprite():set_animation("burrowing")
   --play the sound if you're close enough
    local hero = self:get_map():get_entity("hero")
    local _, _, layer = self:get_position()
    local near_hero = self:get_distance(hero) < 140
    if near_hero then sol.audio.play_sound(properties.burrow_sound) end
    sol.timer.start(self, 800, function() self:go_aboveground() end)
  end

  function enemy:go_underground()
    underground = true
    self:get_sprite():set_animation("underground")
--this code is so you don't get chased by an underground dude
    local m = properties.movement_create()
    if m == nil then
      -- No movement.
      self:get_sprite():set_animation("stopped")
      m = self:get_movement()
      if m ~= nil then
        -- Stop the previous movement.
        m:stop()
      end
    else
      m:set_speed(properties.normal_speed)
      m:set_ignore_obstacles(properties.ignore_obstacles)
      m:start(self)
    end
--]]
    self:set_can_attack(false)
    sol.timer.start(self, (properties.time_underground + math.random(properties.burrow_deviation)), function() self:burrow_up() end)
   
  end

  function enemy:go_aboveground()
    underground = false
    self:set_can_attack(true)
    self:get_sprite():set_animation("walking")
    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 or enemy:has_layer_independent_collisions()) and
        self:get_distance(hero) < properties.detection_distance

    if near_hero and not going_hero then
      if underground == false then self:go_hero()
      else self:go_random()
      end
    elseif not near_hero then
      self:go_random()
    end
--and repeat this every 150ms
    sol.timer.start(self, 150, function() self:check_hero() end)

  end



  function enemy:go_random()
    going_hero = false
    sol.timer.start(self, properties.time_aboveground+math.random(properties.burrow_deviation), function() self:burrow_down() end)
    local m = properties.movement_create()
    if m == nil then
      -- No movement.
      self:get_sprite():set_animation("stopped")
      m = self:get_movement()
      if m ~= nil then
        -- Stop the previous movement.
        m:stop()
      end
    else
      m:set_speed(properties.normal_speed)
      m:set_ignore_obstacles(properties.ignore_obstacles)
      m:start(self)
    end
  end



  function enemy:go_hero()
    going_hero = true
    sol.timer.stop_all(self)
    sol.timer.start(self, (properties.time_aboveground + math.random(properties.burrow_deviation + 2000)), function() self:burrow_down() end)
    local m = sol.movement.create("target")
    m:set_speed(properties.faster_speed)
    m:set_ignore_obstacles(properties.ignore_obstacles)
    m:start(self)
    self:get_sprite():set_animation("walking")
  end



end

return behavior

22
Development / Displaying an image on pause
« on: February 27, 2018, 04:32:05 pm »
Hey all, sorry to kind of flood the board with questions. I've been saving them up for a year trying to figure them out myself first but there's a few I need help with.

So, I've been trying to learn Solarus and lua coding for a year and a half, and I still can't figure out how to create a pause menu. I've basically given up and accepted this as a design limitation to constrain myself with, so my game only has two items. But anyway, all my playtesters have given me the feedback that with all the side quests in my game, they'd really like a main quest log kind of feature because they forget what they were supposed to be doing. I think that just displaying the current stage of the main quest on the pause screen is the way to go.

So from studying the various solarus team scripts, I think that the way to show an image would be something like this:
Code: (lua) [Select]
function game:on_paused()
  local pause_infra_img = sol.surface.create("hud/pause_infra.png")
  local pause_surface = sol.surface.create()
  pause_infra_img:draw(pause_surface)
end

However, I'm really confused about how all this works. It seems like you can create a surface, but it won't be immediately drawn? So you have to draw it, but you need a surface to draw it on. But wouldn't the second surface need to be drawn on a surface too? Ahh!

23
Development / Creating a respawn point on map changed?
« on: February 27, 2018, 04:23:51 pm »
Hi guys!

One thing I dislike about A Link to the Past is that you have to restart at your house or the Pyramid every time you die in the overworld. In the game I'm working on, you spend quite a lot of time in the overworld doing side-quests, and I don't want to set the player back so far if they're killed. I'd like to make it so if you die, you can be taken back whatever map you're currently on.

I know if the player is transported to a new map via a destination, you can save that location for restarting. However, if you use the side of the map scrolling feature, there is no destination to go back to, so one workaround is to design my overworld so there's never any side of the map teletransporters, but I'd like to avoid that if possible.

I also tried dynamically creating a destination using game:on_map_changed() and map:create_destination(), however it seems like the game erases this destination when a gameover happens, because the hero isn't taken back to it. I had this function in my game_manager script. This was my code that doesn't seem to work:

Code: (lua) [Select]
--Set Respawn point whenver map changes
function game:on_map_changed()
  local map = game:get_map()
  local hero = game:get_hero()
  local x, y, layer = hero:get_position()
  map:create_destination({
    name = "respawn",
    x = x, y = y, layer = layer,
    direction = hero:get_direction(),
    save_location = "yes",
    default = true,
  })

But yeah, it seems like that destination is erased whenever a gameover happens, which makes it kind of pointless. Any ideas?

24
Development / Activating a switch from a script?
« on: February 27, 2018, 02:15:30 am »
Hello!

I've been looking over the Solarus Team's bow/arrows script, which is super cool, and developed a script using it that shoots fire arrows. But one problem I'm encountering is that it uses switch:set-activated() to allow arrows to interact with switches. However, this method doesn't trigger the switch:on_activated() event.

I've found a workaround with setting a timer that checks to see if the switch has been activated ever 100ms or so and acts accordingly, but is there a better way to do this? Is there a way to trigger the event from a script?

Thanks!

25
Your projects / Ocean's Heart
« on: February 27, 2018, 01:59:34 am »
Hello! I'm regularly updating this post to reflect progress on this game. Ocean's Heart is a game I started in about March of 2017 in order to teach myself to use the Solarus Engine and learn some coding. The most recent update was October 11th, 2018.
I've been using twitter to regularly post screenshots and news about my game, so follow me there for frequent news!:
https://twitter.com/11mraz

The game follows the journey of a girl whose father left their town six months ago to defeat pirates that attacked and kidnapped another girl. She spends most of the game following his trail and uncovering the plot that's kept him away for so long. I'm aiming for a cross between Zelda: The Wind Waker, and the Witcher 3:Wild Hunt, emphasizing exploration and interesting side-plots. I'm not trying to emulate Zelda in its entirety, so there's a few differences in my approach to dungeons, player power progression, depth of sidequests, etc. The final game is on track to be 5-8 hours long depending on how much exploration the player is interested in.

The game, rough estimate, is about 70% complete. There are currently several islands to explore, a small handful of dungeons (some larger, some smaller), items and abilities to find, many sidequests, and a main quest that I'm estimating might take a few hours to get as far as you currently can. You could reasonably sink 3-5 hours into the game right now if you wanted to exhaust every side quest and find every hidden power-up and treasure. At the moment, I'd like to release Ocean's Heart in 2019, but you know how video game releases go.

I've decided to take down the demo I had for now, since much about the game has changed and it was starting to become less than representative. It's just confusing for the both of us when people ask questions and I've already changed a lot. I'm planning another small demo sometime in the next few months that is a better vertical slice and will stand alone. If you're interested in testing or doing a let's play, send me a message or email and I might be able to hook you up with a playable build!



Here's a short, low-quality trailer of some areas:
(there's no way to embed youtube videos on this forum, is there?)

https://youtu.be/2RySTLSKjUs

And some screenshots:








Pages: 1 [2]