Menu

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.

Show posts Menu

Messages - Max

#211
Your scripts / Deku/Turret Type Enemy
April 28, 2018, 08:10:54 PM
Hey all. Ponderitus in another topic was talking about a script for a deku kind of enemy, and I thought it might work reasonably we as a base for a beamos-type enemy also.

Here's an example of an enemy I threw together quickly for testing that uses this script in action. I call him the stump duck, lol.
https://youtu.be/x7YqHht0B7c




How it works is, basically, the enemy starts out asleep. In its on:restarted event, it makes a check every 100ms or so to see how far away the hero is. There's a max_range and a min_range you set, and if the hero is in between these, the enemy wakes up. If the hero is outside the range, the enemy goes to sleep. Basically, if you're too far or too close, the enemy goes to sleep, during which phase it is invulnerable to swords and arrows. Bombs/fire will still work as I have it, but you can change that.

Anyway, it also has a check_hero function that repeats every 120ms, to see if it can shoot at the player. If the enemy is awake (which means the hero is in range) and aligned for a shot, then it'll shoot whatever projectile breed you've specified. There's a property called must_be_aligned_to_shoot (true by default) that you can set as false to have your enemy more like a beamos or those annoying statues that shoot all the time (medusas? Is that what they were called?)

If you have any questions, let me know. There's a lot of code based on Solarus Team's games, which you might be able to tell from the names of some functions and variables that I copied.

So anyway, here's that:

Code (lua) Select

local behavior = {}

-- The properties parameter is a table.
-- All its values are optional except the sprite.
--This is for an enemy like a deku scrub, one that is invulnerable and perhaps hidden
--unless the hero is close, but not too close. It hides unless the hero is between the
--properties min_range and max_range. When the hero is in this area though, the enemy
--will shoot projectiles at the hero. Use the property must_be_aligned_to_shoot to define
--if the enemy shoots in 360 degrees at the hero or just orthogonally. The projectile_breed
--property ought to be a projectile that compliments this.

--The sprite must have the animations "asleep" "awake" and "shooting". "waking_up" is an
--optional animation that ought to be less than 200ms. The enemy can define the property
--"awakening_sound" for a sound effect to be played whenever the enemy wakes up.

--This enemy is vulnerable to swords and arrows when it is awake (the hero is in range), but
--it is always vulnerable to explosions and fire.

function behavior:create(enemy, properties)

local children = {}
local can_shoot = true
local awake = false
local dist_hero

  -- Set default properties.
  if properties.life == nil then
    properties.life = 2
  end
  if properties.damage == nil then
    properties.damage = 0
  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.size_x == nil then
    properties.size_x = 16
  end
  if properties.size_y == nil then
    properties.size_y = 16
  end
  if properties.hurt_style == nil then
    properties.hurt_style = "normal"
  end
  if properties.pushed_when_hurt == nil then
    properties.pushed_when_hurt = false
  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.projectile_breed == nil then
    properties.projectile_breed = "misc/octorok_stone"
  end
  if properties.shooting_frequency == nil then
    properties.shooting_frequency = 1500
  end
  if properties.sword_consequence == nil then
    properties.sword_consequence = 1
  end
  if properties.arrow_consequence == nil then
    properties.arrow_consequence = 1
  end
  if properties.explosion_consequence == nil then
    properties.explosion_consequence = 1
  end
  if properties.fire_consequence == nil then
    properties.fire_consequence = 1
  end
  if properties.movement_create == nil then
    properties.movement_create = function()
      local m = sol.movement.create("random_path")
      return m
    end
  end
  if properties.asleep_animation == nil then
    properties.asleep_animation = "asleep"
  end
  if properties.awake_animation == nil then
    properties.awake_animation = "awake"
  end
  if properties.must_be_aligned_to_shoot == nil then
    properties.must_be_aligned_to_shoot = true
  end
  if properties.max_range == nil then
    properties.max_range = 100
  end
  if properties.min_range == nil then
    properties.min_range = 45
  end
  if properties.must_be_aligned_to_shoot == nil then
    properties.must_be_aligned_to_shoot = true
  end


  function enemy:on_created()

    self:set_life(properties.life)
    self:set_damage(properties.damage)
    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)
    self:set_attack_consequence("explosion", properties.explosion_consequence)
    self:set_attack_consequence("fire", properties.fire_consequence)
    self:set_attack_consequence("sword", "protected")
    self:set_attack_consequence("arrow", "protected")
--    self:set_traversable(false)

    local sprite = self:create_sprite(properties.sprite)
    function sprite:on_animation_finished(animation)
      -- If the awakening transition is finished, make the enemy go toward the hero.
      if animation == properties.awaking_animation then
        enemy:finish_waking_up()
      end
    end
    sprite:set_animation(properties.asleep_animation)

  end

  function enemy:on_movement_changed(movement)

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

local previous_on_removed = enemy.on_removed
function enemy:on_removed()

  if previous_on_removed then
previous_on_removed(enemy)
  end

  for _, child in ipairs(children) do
child:remove()
  end
end


  function enemy:on_restarted()
    can_shoot = true
    if awake == true then self:get_sprite():set_animation("awake") else self:get_sprite():set_animation("asleep") end
  local map = self:get_map()
  local hero = map:get_hero()
    dist_hero = enemy:get_distance(hero)
    self:check_hero()

    --check if enemy needs to wake up or go to sleep based on if hero is near. Repeat every 80ms
  sol.timer.start(enemy, 100, function()
      dist_hero = enemy:get_distance(hero)
      if dist_hero < properties.max_range and dist_hero > properties.min_range and awake == false then
        self:wake_up()
      end
      if dist_hero > properties.max_range or dist_hero < properties.min_range then
        if awake == true then self:go_to_sleep() end
      end

      return true
    end)
  end--end of on:restarted function



  function enemy:check_hero()
  local map = self:get_map()
  local hero = map:get_hero()
    local direction4 = self:get_direction4_to(hero)
    local sprite = self:get_sprite()
    sprite:set_direction(direction4)
    dist_hero = enemy:get_distance(hero)
    local _, _, layer = self:get_position()
    local hero_x, hero_y, hero_layer = hero:get_position()
    local x, y = enemy:get_center_position()
    local aligned

    if awake == true then
      --see about shooting
      if properties.must_be_aligned_to_shoot == true then
        if ((math.abs(hero_x - x) < 16 or math.abs(hero_y - y) < 16))
        and layer == hero_layer
        then
          aligned = true
        end
      else
        if layer == hero_layer then aligned = true end
      end

      if aligned == true and can_shoot == true then
        self:shoot()
        can_shoot = false
        sol.timer.start(enemy, properties.shooting_frequency, function() can_shoot = true end)
      end

    end --end if awake=true condition


    sol.timer.start(self, 120, function() self:check_hero() end)
  end --end of check hero function


  function enemy:wake_up()
    self:stop_movement()
    if properties.awakening_sound ~= nil then
      sol.audio.play_sound(properties.awakening_sound)     
    end
    if properties.waking_animation ~= nil then
      local sprite = self:get_sprite()
      sprite:set_animation(properties.waking_animation)
    end
    sol.timer.start(self, 200, function() self:finish_waking_up() end)
  end

  function enemy:finish_waking_up()
    self:get_sprite():set_animation(properties.awake_animation)
    awake = true
    self:set_attack_consequence("sword", properties.sword_consequence)
    self:set_attack_consequence("arrow", properties.arrow_consequence)
  end


  function enemy:go_to_sleep()
    self:stop_movement()
    if properties.awakening_sound ~= nil then
      sol.audio.play_sound(properties.awakening_sound)     
    end
    sol.timer.start(self, 200, function() self:finish_going_to_sleep() end)
  end

  function enemy:finish_going_to_sleep()
    self:get_sprite():set_animation(properties.asleep_animation)
    awake = false
    self:set_attack_consequence("sword", "protected")
    self:set_attack_consequence("arrow", "protected")
  end



function enemy:shoot()
  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()

  -- Where to create the projectile.
  local dxy = {
{  8,  -4 },
{  0, -13 },
{ -8,  -4 },
{  0,   0 },
  }

  sprite:set_animation("shooting")
  enemy:stop_movement()
  sol.timer.start(enemy, 300, function()
  sol.audio.play_sound("stone")
  local stone = enemy:create_enemy({
    breed = properties.projectile_breed,
    x = dxy[direction + 1][1],
    y = dxy[direction + 1][2],
  })
  children[#children + 1] = stone
  stone:go(direction)
    sprite:set_animation(properties.awake_animation)
      self:check_hero()
  end)
end

end

return behavior




And here's an example of an enemy that uses this code:

Code (lua) Select

local enemy = ...


local behavior = require("enemies/lib/turret")

local properties = {
  sprite = "enemies/" .. enemy:get_breed(),
  life = 10,
  waking_animation = "wake_up",
  awakening_sound = "bush",
  must_be_aligned_to_shoot = true,
}

behavior:create(enemy, properties)




Your projectiles will need a function called enemy:go(direction) that can take an argument for their direction, as shown in these examples. Here's a projectile that goes in orthogonal directions, borrowed from Solarus DX:

Code (lua) Select

-- Stone shot by Octorok.

local enemy = ...

function enemy:on_created()

  enemy:set_life(1)
  enemy:set_damage(2)
  enemy:create_sprite("enemies/" .. enemy:get_breed())
  enemy:set_size(8, 8)
  enemy:set_origin(4, 4)
  enemy:set_invincible()
  enemy:set_obstacle_behavior("flying")
  enemy:set_attack_consequence("sword", "custom")
end

function enemy:on_obstacle_reached()

  enemy:remove()
end

function enemy:go(direction4)

  local angle = direction4 * math.pi / 2
  local movement = sol.movement.create("straight")
  movement:set_speed(150)
  movement:set_angle(angle)
  movement:set_smooth(false)
  movement:start(enemy)

  enemy:get_sprite():set_direction(direction4)
end

--destroy if hit with sword
--
function enemy:on_custom_attack_received(attack, sprite)

  if attack == "sword" then
  enemy:remove_life(1)
  end
end
--]]



And here's one that will go in any direction, also adapted from Solarus DX:

Code (lua) Select

-- 3 fireballs shot by enemies like Zora and that go toward the hero.
-- They can be hit with the sword, this changes their direction.
local enemy = ...

local sprites = {}

function enemy:on_created()

  enemy:set_life(1)
  enemy:set_damage(2)
  enemy:set_size(8, 8)
  enemy:set_origin(4, 4)
  enemy:set_obstacle_behavior("flying")
  enemy:set_can_hurt_hero_running(true)
  enemy:set_invincible()
  enemy:set_attack_consequence("sword", "custom")

  sprites[1] = enemy:create_sprite("enemies/" .. enemy:get_breed())
  -- Sprites 2 and 3 do not belong to the enemy to avoid testing collisions with them.
  sprites[2] = sol.sprite.create("enemies/" .. enemy:get_breed())
  sprites[3] = sol.sprite.create("enemies/" .. enemy:get_breed())
end

local function go(angle)

  local movement = sol.movement.create("straight")
  movement:set_speed(175)
  movement:set_angle(angle)
  movement:set_smooth(false)

  function movement:on_obstacle_reached()
    enemy:remove()
  end

  -- Compute the coordinate offset of follower sprites.
  local x = math.cos(angle) * 10
  local y = -math.sin(angle) * 10
  sprites[1]:set_xy(2 * x, 2 * y)
  sprites[2]:set_xy(x, y)

  sprites[1]:set_animation("walking")
  sprites[2]:set_animation("following_1")
  sprites[3]:set_animation("following_2")

  movement:start(enemy)
end

function enemy:on_restarted()

  local hero = enemy:get_map():get_hero()
  local angle = enemy:get_angle(hero:get_center_position())
  go(angle)
end

-- Destroy the fireball when the hero is touched.
function enemy:on_attacking_hero(hero, enemy_sprite)

  hero:start_hurt(enemy, enemy_sprite, enemy:get_damage())
  enemy:remove()
end

-- Change the direction of the movement when hit with the sword.
function enemy:on_custom_attack_received(attack, sprite)

  if attack == "sword" and sprite == sprites[1] then
    local hero = enemy:get_map():get_hero()
    local movement = enemy:get_movement()
    if movement == nil then
      return
    end

    local old_angle = movement:get_angle()
    local angle
    local hero_direction = hero:get_direction()
    if hero_direction == 0 or hero_direction == 2 then
      angle = math.pi - old_angle
    else
      angle = 2 * math.pi - old_angle
    end

    go(angle)
    sol.audio.play_sound("enemy_hurt")

    -- The trailing fireballs are now on the hero: don't attack temporarily
    enemy:set_can_attack(false)
    sol.timer.start(enemy, 500, function()
      enemy:set_can_attack(true)
    end)
  end
end

function enemy:on_pre_draw()

  local map = enemy:get_map()
  local x, y = enemy:get_position()
  map:draw_visual(sprites[2], x, y)
  map:draw_visual(sprites[3], x, y)
end
#212
Game art & music / Re: Oceansheart Graphics
April 27, 2018, 04:26:55 AM
I'll create one eventually : )
I don't have one for this yet because I work from an in-progress, very messy tileset that nobody else would want to try to use (there is SO much scrolling when I'm mapping). Once I've finished mapping my game, I'll probably have a lot more graphics to share, and I'll probably re-arrange some things. So I'll create a .dat then, to avoid having to create two. But one will arrive eventually!
#213
Your projects / Re: Ocean's Heart
April 26, 2018, 06:33:14 PM
Yeah, I don't know if you saw, but in another topic I released some of the tiles from the game for public use. However, it's not intended to be a complete release yet, since I'm still making tiles for the game as I go. I'm planning on releasing a more complete tileset after I've finished the game, for everyone to use.

But once that's done, you'll be more than welcome to use it for a Solarus Resource pack!
#214
Your projects / Re: Ocean's Heart
April 26, 2018, 11:01:38 AM
Cool, I'll look forward to that for 1.6!

And thanks for doing a let's play! I randomly saw it as I was watching Mark  Brown's newest YouTube video,which  was a fun surprise. It a lot of fun to watch! I also got like 6 or 7 notes or small mistakes to fix, which is good. And thanks so much, I'm glad you enjoyed it and think so much of the graphics.

A couple questions you brought up on your let's play I can answer:

-There is a world map- press M : )
-The resolution is indeed 320x240
-There are still a mix of Zelda and custom sound effects. It's going to take a while to replace them all.
-100% of the graphics are my own. (The wooden corner pilliars that you mentioned look similar to yours are because we both based them off Minish Cap's corners, and they're both corners of walls 32px tall, so they're bound to look similar.)
-If I were to estimate, you got maybe 20% of the way through what I've completed so far.
-As far as the dialogues, I definitely use a lot of informal and colloquial language, and also a bunch of specific sea creatures and plants in my writing. Since English isn't your first language, you did a great job! I hadn't thought how odd some of my words might seem (for example, an Egret is a type of bird)


One last thing, a clue for the quest about the phantom squid, if you want it. You were veeeery close and just missed something by a couple pixels in that house. I'm going to go in and take out all the books except the bookshelf after seeing you play through it.

Anyway, thanks again for playing! I look forward to seeing you play more if you do. If you have any other questions, let me know.
#215
Your projects / Re: Ocean's Heart
April 25, 2018, 07:17:00 PM
And of course, you have the work arounds of placing all plants taller than 16x16 just south of a tree or wall, or avoiding the issue altogether by not creating destructables larger than 16x16, which seems right now like a better solution than all the coding of replacing bushes with custom entities.

Just curious, is there a reason destructables are like this, or did we just not think we might want some larger than 16x16 because Link to the Past only had 16x16, so it just wasn't considered?
#216
Your projects / Re: Ocean's Heart
April 25, 2018, 05:01:34 PM
Thanks Christopho! I've gone ahead and uploaded a slightly newer version to the first post, I fixed just a couple bugs, there's still a few I'm aware of that I haven't had time to fix yet (the yellow plants thing, you can jump through a few of the ships still, etc.). But as far as I'm aware, you can progress through the main story all the way up to the city of Oakhaven (you can get it, but it's unfinished), and any sidequests you can find should all work.

Here's a link to the newer version here also:
Ocean's Heart 0.1.3

Have fun!




Diarandor, regarding the flowers, I attached a screenshot to this post-
the problem is that the plants I'm using have a 16x16 hitbox, but are approximately 16x24 sprites. When this is the case with say, a 16x32 NPC, what happens is the player can walk "in front of" and "behind" them. When you're "in front of" an npc, that is, your Y coordinate is higher, then the player is drawn above the npc. When you're "behind" the npc, or your Y coordinate is lower, the player is drawn behind the NPC.
My problem is that this isn't the case with destructibles, such as a bush. The player is drawn above the bush no matter their Y coordinate, making it impossible to walk "behind" a bush. If you've only got 16x16 destructibles, this is't a problem, but I have a couple that are 16x24, and I was anticipating they've behave like NPC sprites.
#217
Development / Re: Setting Up A Basic Equipment Menu?
April 25, 2018, 03:45:02 PM
Hey Bagu- I agree, item menus are hard! I haven't figured one out yet either, I literally designed my game to only have two items so I wouldn't need to do one, in my opinion menus are definitely the hardest part of designing in Solarus. My best advice is to start learning by making a static menu- one that will come up and display information, but you can't interact with (a quest status screen, for example) before you get into an item menu. And once you start trying to figure that out, be sure to post a topic explaining how you're doing it so I can learn from you! : )

Ponderitus, thanks for the compliments. BTW, if you want that deku enemy, you'll need a function that has a "check hero" thing every 100ms or so and gets the distance to the hero, then if that distance is >100 or whatever, remain asleep, if it's <100 and >32, wake up and shoot, and if it's <32, go back to sleep. If you want more help, post a topic about it and I'm pretty confident I have code that will work.
#218
Does an official Dev kit mean we'd be able to put our games up in the switch shop? I'd definitely be into donating to a crowdfunding thing for that!
#219
Your projects / Re: Ocean's Heart
April 18, 2018, 10:31:10 PM
Super helpful critique,thanks! Also curious, how far did you get, and were you bored any of the time?

I'm aware of a couple of these and working on fixes long-term. I'm planning on using a dialog system where I turn the font blue when Tilia is speaking, I've had some help on that and just haven't gotten around to implimentation.

For the actionkey, I'm trying to just train the player to investigate everything using dialog feedback as reward. I've tried to provide descriptions of all the books and notes laying around.


The tall yellow plants (forsythia) are something I don't know how to fix. If the whole sprite is drawn above the hero in y-order, wouldn't her head go under the plant when you walk south of it? I had figured that destructables would be like enemies, would have their 16x16 hitbox drawn below the hero, and above that would display above the hero if they're to the South of her, or below the hero if the plant is to the north of her. But they don't seem to work like enemy sprites in this regard...

#220
Game art & music / Re: Oceansheart Graphics
April 16, 2018, 12:55:45 AM
Oh hey, I totally missed that you posted your edits, Froggy! Cool. I especially like how you've colored the purple/brown roof into a wooden texture, that looks great. The crenelations you added to the tower are also cool, that might help people who are making a castle (which, since Zelda games usually always have a castle, that's probably a lot of people, haha). Nice work!

What was your process to reduce the number of colors?

#221
Game art & music / Re: Original art
April 09, 2018, 04:03:17 AM
Having them drag the hero when he's using his shield is an awesome idea. I could see interesting puzzles developing- can the tongue grab other things too?
#222
General discussion / Re: Some Zelda-like games
April 06, 2018, 04:52:32 AM
Certainly does look cool- and professional! They've got a pretty responsible 4-year anticipated development window.

I read this interview with one of the developers too:
http://www.nintendolife.com/news/2018/03/feature_snes-style_rpg_hazelnut_bastille_coming_to_switch_with_secret_of_mana_composer_in_tow

You can tell he's thought a lot about this type of game's design. Interesting especially to me are his thoughts on level design prioritizing clarity of collisions and readability. That's something a lot of modern games (in our attempts to use our technology to make them pretty) overlook (looking at you, hyper light drifter).
#223
Game art & music / Re: Oceansheart Graphics
April 05, 2018, 06:31:45 PM
Absolutely! I'm glad you think it's worth investing some time into improving : )
#224
Development / Re: Solarus Engine Roadmap?
April 04, 2018, 09:17:17 PM
I tried playing it some today. I didn't see any typos- some of the sentences in english were phrased a little bit weirdly, but it all made sense  ;D

I also noticed a bunch of things felt broken. For example, the pegaus shoes would run in a random direction and were completely useless, the feather often made me jump diagonally instead of straight and fall into holes, which killed me a few times, and it seemed like I was supposed to keep feeding zelda's cat, cutting the grass, and getting her mail forever, which wasn't really any fun to do. Are these things bugs, or intentionally designed to make the player frustrated? I couldn't figure out how to get further than those jumping miniboss guys in the castle, and I kind of gave up because the game felt so broken. But maybe that was part of the joke? I'm trying not to seem mean, maybe this kind of humor just isn't for me. I thought the joke about Zelda taking away Link's lightsaber was funny though.

Anyway, as far as I could get, even if the game felt like it was either full of bugs or designed to make it frustrating to play, the translation at least seems fine! The menus and items that did work worked very well too.
#225
Game art & music / Re: Oceansheart Graphics
April 01, 2018, 08:04:01 AM
Thanks Diarandor, I'm grateful for all the help I've received on the forum.

Neovyse, I appreciate the critiques. I also found the thatched roofs (as well as the tall yellow grass) to be very bright and colorful, but when I tried different colors, they all felt too sad and dull. If you want to recolor anything, feel free! I couldn't find other colors that toned it down without feeling too dull, but maybe you can!

I never noticed the flat bit of the tree, but you're right. As for the shading on the spruce tree, that's also valid. I used one less color on it compared to some of the other trees, because I didn't want it to stand out
as much. One thing I've encountered in this project is that with trees especially, it's a difficult balance to make them stand out enough from the ground and other scenery,without standing out too much and looking busy, as they're often really just background elements. Maybe I'll try making another spruce. Trees are maybe my favorite thing to draw, although the perspective is very difficult.

Side note, just because I love plants- these are meant to be fir or spruce trees. Pines rarely grow in such a cone-shaped form, they naturally drop their lower branches and end up more like the trees directly above them. It's not really important, but I do think in the business of creating tiles meant to represent the natural world, our art can be greatly enriched by a deeper understanding of the things we mean to emulate. The usual thing, in tilesets, is to have one tree and maybe one conifer tree. However- people usually create one "generic" tree. But which tree is it? That's so frequently a weakness 2D games have in representing the natural world,and it makes it hard to convey a sense of the world you've created. Where I live, I can go to a forest on one side of town, and it's fairly wet, full of maples, elms, and Ash trees, each of which are different. But on the other side of town, there are forests on hills full of hickoy and oak trees. Both forests feel totally different to me, and if, as artists, we don't bother to learn about what makes various parts of the natural world feel different, or learn the details of various environments, we can only create generic areas. A forest, or a desert. If we study, we could easily have five different forests in a game that all feel totally different.

Sorry, rant over. I plan someday to write like, an article about how to study the natural world in order the create unique areas in games. But that's why it was important to me to make so many trees for my game. In this tileset, there's apple, american basswood, white pine, oak, poplar, and spruce. Granted, it's really hard to convey them well in 2D at this perspective, but it's important to me to try, haha. I hope others will be inspired to more fully utilize the amazing diversity of the natural world to create works of art that make the player feel like they're in a particular part of nature.