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

Topics - Satoh

#1
So, I find a lot of circumstances where I need to push or pull the player around, but I don't want them to lose the ability to push and pull in return...

That is, objects that suck the player toward them or push them away, or platforms that move around, but the player can always move around in conjunction with this other applied force.

I know this CAN be done by calling hero:set_position(...) in a timer, but as I've been finding multiple reasons to need to do this, I'm starting to think I should at least ask if I'm doing it the hard way and there actually is some way to multiply force vectors together on an existing movement or something... yknow, just literally anything other than continually hardcoding the hero's X and Y positions, which I'm led to believe is somewhat going against the 'intent' of solarus' movement system.

(I noticed that if I call a timer at 0ms interval, and move the hero 1 px each time, it only equates to about 60 px/s, as a hero walking at speed 60 will basically stand still under that force, using my method... but 0ms and 1px SHOULD be a force >1000px/s... interestingly enough this force does drastically decrease when set to 1ms interval, such that a player moving at speed 60 can easily walk right through it. This is the other reason I want a different 'better' method. I can't control the 'speed' in a logical way using timers and set_position... it just doesn't behave the way it logically should, given that 1 pixel every millisecond equals 1000px/s, and the timer system only seems to go as high as 60px/s.)
#2
Development / [SOLVED]Change map graphics during play
December 04, 2017, 02:25:25 AM
I want to change the colors of the map, either to harsh black and white or some sort of inverted color or some similar effect.

I don't have the slightest idea of how that might be accomplished. My instinct is that it isn't possible with the current version of solarus...
I didn't see any functions that dealt directly with tilesets, and I don't think maps are drawn as Drawables that can be altered using blend modes...

I'm asking as a sort of last resort, does anyone have any ideas how I might change the look of the map in real time? (the whole map at once)
#3
Bugs & Feature requests / Sword tapping crash
November 28, 2017, 11:59:02 PM
I feel like I encountered this once before but I can't find a post about it and the bug tracker doesn't seem to mention it either...
I'm also not sure if I'm supposed to ask before posting to the bug tracker... so I'll explain it here and wait for advice.

If I define a sword_tapping animation that has fewer than 7 frames the game will either crash, or lock the hero into a tapping state, depending on loop flags.
(I did ensure that I had a tapping animation for both sword and hero.)

My animation only required 2 frames of animation (Link's Awakening style). If I set the animation to 2 frames, not looping, on the Sword, the game crashes stating that there is no animation for Sword's sword_tapping.

If I set the animation to loop, the Hero continually taps the sword without ever stopping.

If I stretch the animation to have 7 frames, everything works normally again. (Except I had to make a new texture for the animation because it didn't fit the other file anymore, but that's just an OCD thing.)
#4
Bugs & Feature requests / hero:set_size
November 23, 2017, 11:49:51 PM
This one just keeps being a problem every time I have an idea to use solarus for.

LTTP is a sot of odd game in that its the only free movement game I've ever played where the hero actually takes up a full 16x16 collision rectangle.

Every other game I can think of from Chrono Trigger to Seiken Densetsu, to almost every 2D Zelda game has allowed the bounding box to be smaller than a full map tile and also allowed the player's sprite to clip into the wall a little bit.

For example, I know that Link's sprite in both Oracle games and Link's Awakening ( and LADX ) is 16x16, but his collision area is only 8x10, focused at the bottom center of his feet. He doesn't clip into the wall from the bottom, but he has a little room to walk around inside a 1x1 tile (16x16px) box, and a bit of space to gently kiss the walls.

In Minish Cap, Link's bounding box is 11x8 while his sprite is 18x24.

In The Legend of Zelda (NES) Link is 16x16px in sprite size, but his bounding box is only 16x8.

This is a feature that is extremely important to me for both accuracy and game-feel, as well as aesthetics.

I tried adding the set_size function to the hero entity list and recompiling solarus, but with all the library dependencies and compiler quirks, I couldn't get the thing to compile. After 8 hours (no I'm not exaggerating) I gave up.

Could you be so kind as to consider making the player's size alterable. The engine seems to be coded well enough that it shouldn't break anything, since it doesn't cause any problems for other entities.


EDIT:
I notice now that this has been recently discussed partially in another thread.
I'm leaving this here for emphasis and potential discussion of why it would be useful.
#5
As I try to code an entity that can be picked up and placed, I find myself becoming somewhat overwhelmed by all the cases I'd have to test for to ensure that the hero behaves correctly as though the 'carrying' state is set.

Not only do I have to make sure the entity works, but also the hero itself.

I find that it would be much simpler if it was possible to turn an entity into a carried_object, having it fire events when lifted, when released/thrown/placed/whatever, and when destroyed... If those were accessible it would be somewhat trivial to create a variety of non-standard liftables, such as those that are placed gently when let go, those that are thrown but don't explode, and even some that are destroyed immediately upon being lifted (if that was needed).

Not being able to access the hero's state directly, or pass an entity to the hero as a carried_object reference, largely prevents me from doing that.

(specifically I'm currently just trying to make an object that remains on the map when set down, and isn't automatically tossed across the room... its more difficult than I imagined when I started.)

As for a Zelda related example of an object that fits this pattern, Link's Awakening (as Diarandor reminded me) has an iron ball, which I believe was used in either a boss battle or puzzle. Link would lift it and throw it back at the boss, or try to topple a pillar with it or something, but it wasn't destroyed when it was thrown. Instead, it rolled around a little bit (and could also be pushed, like a big marble)

Hard-coding all of that behavior wouldn't be necessary, as that could largely be handled by custom_entity scripting, if it was possible tell the hero that the entity should be carried.

I feel like there are a lot of built in features that would be a lot more flexible if they had some more lua control, but most of those features can be recreated to an extent using items or entities... lifting and carrying seems to be a much more complicated problem on the other hand.

But as the title states, this is less a formal request and more of a suggestion for how the engine might be more flexible.
#6
Development / Lifting a custom_entity?
July 11, 2016, 06:02:06 AM
so, I've been coding a custom entity that I can push around and lift...
Pushing isn't really a problem, but I've run into a curious issue...

I don't know how to tell the engine the hero is in the lifting or carrying states, nor how to generate a carried object...
I can't simply use a destructible, since the hero will be setting down the object later...

I can probably add a 'set_state(param)' to type hero if I alter the metatable... but even so, that won't automatically create a carried object... and the documents don't seem to suggest that it is possible to do so through the lua interface...

Am I going to have to code everything from the lifting to the walking, and placing/throwing manually?
For the first time in a while I'm 100% stumped as to how to proceed.
#7
I need to manually switch the hero's layer, without altering their position, instantly. (For reasons dealing with how collision happens, which are too complicated to explain for the purposes of this question)

What I've tried is:
local entity = ...
entity:set_size(16,16)
entity:set_origin(8,12)
entity:add_collision_test("origin", function(me, other) 
  debug.message = "layerchange"
  local posx,posy,posl = other:get_position()
  other:set_position(posx,posy,math.min(posl+1,2))
end)


Now... this all works as it seems like it should, except that it does not change the layer.
I also tried this in the debug console by simply accessing sol.main.game:get_hero():set_position(hero x,hero y, new layer)
and the hero does move to whatever hero x and hero y are, but new layer is ignored.

In short, hero:set_position() is ignoring the layer no matter what I do... is there another way to handle layer switching?
(Stairs force the player to move, which is not what I want to happen, I just want the hero to be on a different layer, at the same location)

EDIT:
Other entities that move across this layerswitch entity DO get their layer's changed... Only the hero is ignored.
#8
The documentation directly states:
Quote
A carried object is created automatically by the engine when the hero lifts a map entity. Map entities that can be lifted include destructible objects and bombs. The carried object takes the sprite and the features of the lifted entity it is created from.

The hero can then walk with his carried object and throw it. He can even go to another map: the carried object is preserved.
I tried this by creating a destructible object, and carried it to a teletransporter into the next map, but when I arrived at the next map, there was no longer an item being carried and the character's state has been set back to "free" rather than "carrying".

Is this a bug, or ambiguity on the part of the documentation?
#9
SDL has four blend modes, SDL_BLENDMODE_NONE, SDL_BLENDMODE_BLEND, SDL_BLENDMODE_ADD, and SDL_BLENDMODE_MOD.
SDL_BLENDMODE_NONE isn't terribly useful for Solarus so we can ignore it.

Solarus source code appears to always use BLEND already, which makes sense.
My desire is to be able to have some surfaces specify the ADD and MOD modes.
ADD is useful for creating brightly shining effects which lighten and color things under them, without washing them out or making them look hazy. Using a semitransparent sprite or surface by itself would cause the sprite underneath to lose some of its clarity.
If you wanted a particularly bright special effect, it would destroy the clarity of the scene beneath it, whereas an ADD blended surface would allow more of the detail to show through.
It would look better particularly when a dark and light colored object are beneath it, as the dark object would would be lit proportional to its original color.
A simple BLEND effect would cause the darker object to seem to be lit more, due to the BLEND surface partly replacing the scene, rather than adding to it.

Similarly MOD can be used to darken a scene, and add really rich vibrant color to it, without degrading image quality. This is fairly easy to demonstrate, using a screenshot from another SNES game.


At the top we have a BLEND mode style layering, with a blue color, at 75% opacity. It... doesn't look so great, and I wasn't able to make it much darker than that without the image turning more black than blue. Below that is a MOD style layer, which darkens the image with a rich blue color, without making the scene hazy, and it looks like a nice nighttime effect.

With the MOD blendmode, one could make an active day and night cycle by rendering a surface with different colors for different times of day, or shadows which darken sprites under them, without making them look smoky (like what happens with a black or gray semitransparent BLEND shadow)

As far as I could locate, the git src only sets the blendmode twice, so it seems like adding a blendmode property to the solarus drawable class and passing that as an argument, should work... But that's only as far as I could find. I'm sure Christopho knows the source better than I.

Anyway, that's my argument for why it would be a decent feature to have.
#10
When I click the button to create a Block, in the map editor, the program crashes immediately.
The same happens with Crystal and Crystal Block. This is in snapshot 20160620.
#11
I'm trying to create an entity that, when overlapped, an entity that is moving left or right, is forced to move diagonally down and left, up and right, and another entity that does the opposite diagonals, up_left down_right.

I started with this code, but I don't really get what I'm doing with all the collision tests...
and I can't seem to figure out how to control the Hero without taking the control away from the player too.
local entity = ...
--This entity forces the player into diagonal motion
--if the entity is facing LEFT the character will move DOWN and LEFT
--  or UP and RIGHT
--if the entity is facing RIGHT the character will move DOWN and RIGHT
--  or UP and LEFT

local hero = entity:get_map():get_hero()

function entity:on_created()
  self:add_collision_test(function entity:overlaps(hero,"overlapping")
    return true
  end, entity:on_traversed())
end

function entity:on_traversed()
  if self:get_direction() == 0 and hero:get_direction() == 0 then
    -- here is where I'm stuck. The API reference isn't giving me enough info to figure it out.
  end
end


My game will have some large 'sloped' floors, such as staircases, that will simply not look good if the player is allowed to move in straight left and right directions when traversing them.

As my comment in the code states, I'm not sure how to control the hero's direction, without removing player control completely.
I want the player to act freely as they normally would, but simply move in the specified diagonal directions when moving.

I'm also not certain I'm using add_collision_test correctly for a custom entity. I don't know how to get a reference to 'what entity is colliding with self' in order to perform actions on it or do tests from it, as the API reference does not say that any collision tests return any entity references.

In short, I need help and am severely confused. (though I understand lua a lot better than I did the last time I was here, so yay~)

EDIT:
Ok, I found a method that does technically work, but I fear there may be some weird repercussions for certain things I didn't account for due to complexity... if someone has suggestions I'd like to hear them.
new code:
local entity = ...
--This entity forces the player into diagonal motion
--if the entity is facing LEFT the character will move DOWN and LEFT
--  or UP and RIGHT
--if the entity is facing RIGHT the character will move DOWN and RIGHT
--  or UP and LEFT

local hero = entity:get_map():get_hero()
local game = entity:get_map():get_game()
local simulating = nil

function entity:on_update()

  if self:overlaps(hero,"overlapping") and hero:get_state() == "free" then
    if (self:get_direction() == 0 and game:is_command_pressed("right")) or
      (self:get_direction() == 2 and game:is_command_pressed("left")) then
      game:simulate_command_pressed("down")
      simulating = "down"
    elseif (self:get_direction() == 0 and game:is_command_pressed("left")) or
      (self:get_direction() == 2 and game:is_command_pressed("right")) then
      game:simulate_command_pressed("up")
      simulating = "up"
    end
    if self:get_direction() == 0 then
      if not game:is_command_pressed("left") and simulating == "up" then
        game:simulate_command_released(simulating)
        simulating = nil
      end
      if not game:is_command_pressed("right") and simulating == "down"  then
        game:simulate_command_released(simulating)
        simulating = nil 
      end
    end
    if self:get_direction() == 2 then
      if not game:is_command_pressed("left") and simulating == "down" then
        game:simulate_command_released(simulating)
        simulating = nil
      end
      if not game:is_command_pressed("right") and simulating == "up"  then
        game:simulate_command_released(simulating)
        simulating = nil
      end
    end
    if (simulating == "up" and game:is_command_pressed("down")) or
      (simulating == "down" and game:is_command_pressed("up")) then
      game:simulate_command_released("up")
      game:simulate_command_released("down")
      simulating = nil
    end
  elseif simulating ~= nil then
    game:simulate_command_released(simulating)
    simulating = nil
  end
end
#12
While I like the engine as it is, and I'm glad it works as well as it does, there are often little tweaks I'd like to make to some of the Hero's behavior.

Some of these, like changing animations, can be done sort of easily.... but changing the range of a sword strike seems to require a full source mod.

What I'd like to see is the ability to modify some things in the default behavior, from Lua.

There are also times when having a full 16x16 is a bit too large for collision, especially if you're making a game with a smaller character. (I think Link was actually 12 or 14 originally, to allow for a slight amount of wall overlap. If nothing else its a common thing in GBA and SNES games anyway.)

Allowing Lua to modify the Hero behaviors would add a lot of flexibility. Especially since all the other entities in the engine are Lua based.

What I had in mind is "Use default behavior, but allow Lua to override functions by name."
What would be less flexible, but probably a lot easier, would be redirecting the hard coded parameters like sword length (14) to a settings variable, which can be changed.

(Some of the things I had in mind to want more flexibility with are sword behavior and length, bow behavior such as nocking an arrow but not firing until the command is released, shield behavior like manually blocking, allowing for a throwing animation, which there doesn't seem to be, and so forth)


Secondly, a debug console to print messages to would be helpful for error testing.
#13
Development / Custom Entity: Companion
January 21, 2015, 06:32:23 AM
Ok, so I think a custom entity is what I need for this.

I want to make an object that follows and orbits the hero across multiple maps.
In this case something like a fairy or a spirit orb or the like.

There are a few problems I have, mostly because I'm not sure how the engine does them (if it does them).

The first thing is blending modes: Add and Multiply.
The SNES could overlay sprites as transparent objects that would add to the brightness of pixels beneath them (this is how they made sunbeams and torch lights work for example), but this is Solarus, not SNES. I'm not sure if it supports this currently. (the method for implementing it isn't hard if you can modify pixel arrays. In case you need to add it, the general logic is like this:

foreach spritepixel //we only need to mess with the sprite
{
  final_R = Math.Min(screen_R + sprite_R, 255); //If the result is bigger than a byte, we clamp it.
  final_G = Math.Min(screen_G + sprite_G, 255);
  final_B = Math.Min(screen_B + sprite_B, 255);
  //Additive sprites usually don't need alpha since black + any color = no change.
  //so we'll ignore the alpha channel.
  //Obviously this is not in C++ syntax, but I'm sure you're able to fix that easily.
}

I don't think I can do it directly from Lua, judging by how solarus handles drawing, and there's no mention of blending modes. If it's not in the engine, consider this a feature request.

Moving on.
I know exactly how I want the orbit to work, but I'm not certain if it works in Solarus.
local entity = ...
local hero = map:get_entity("hero")
local acceleration = 0.2
local maxspeed = 4.0
local xspeed = 0.0
local yspeed = 0.0
local sprite2 = nil
local x = 0.0
local y = 0.0

function entity:on_created()
  self:create_sprite("entities/faeglow")
  self:set_size(8, 8)
  self:set_origin(4, 4)
  x, y = self:get_position()
  self:set_position(x, y, 2)
  self:get_sprite():set_animation("faeglow")
  sprite2 = sol.sprite.create("entities/faewings")
  sprite2:set_animation("faewings")
end

function entity:on_update()
  local hero_x, hero_y = hero:get_position()
  x, y = self:get_position()
  --Each direction gets a unique check because the entity accelerates each way separately.
  --This creates a nice simple sinusoidal motion and allows the object to follow a fluid organic
  --path to and orbit around its destination, instead of stopping.
  if hero_x > x and xspeed < maxspeed then
    xspeed += acceleration
  end
  if hero_y > y and yspeed < maxspeed then
    yspeed += acceleration
  end
  if hero_x <= x and xspeed > -maxspeed then
    xspeed -= acceleration
  end
  if hero_y <= y and yspeed > -maxspeed then
    yspeed -= acceleration
  end
  --now we actually change the position.
  self:set_position(x+xspeed, y+yspeed)
end

function entity:on_pre_draw()
  self:get_map():draw_sprite(sprite2, x, y)
end


I believe this should work, but I'm not entirely certain if the engine can handle decimal positions, and I'm not sure if this is all I need.

Lastly, I don't know how to make this be a global entity. I've considered making it some kind of item that's simply always in use... but I'm not sure if that would work either.

So, can I get some advice?
#14
Bugs & Feature requests / Sword animation speed bug
January 07, 2015, 04:33:03 AM
I'm terrible at introductions so I'll jump right into what I wanted, and what I did.

I was trying to make the sword swing faster, so the character could move around without being rooted to the ground for so long. (something more like Zelda GBC games)

After I discovered the sword attack is not exposed to editing in Lua... at least as far as I could find, I decided to change the animation speed instead.
This is where the bug happens.

No mater what speed the sword animation is set to, whether its Animation Delay=1 or 500, the sword swinging does not change at all.

I thought the settings might not be getting saved, so...
I tested this by changing the sprite image for the sword. The sword in game looks different, but the swing is the same speed.

How can I modify the sword behavior?
Should I create a new item entirely for it?