Top Down Adventure with Kenmi CuteFantasy Asset Pack

I’ve been working on this project off and on since April. Back then I wrote this blog post and asked a few people for some feedback about how the movement felt.

That version is very outdated now and I hesitate to suggest that you try it now.

You can get a more modern look at what the game is from this post

I was ready to quit working on the game at this point and had taken a month off from looking at it. But I eventually started back up at a slower pace.

I really should be pushing for another feedback request version. But I’ve been refactoring and trying to deal with some technical debt issues that are maybe making it less pleasant to work on.

On a whim I recorded a YouTube video and uploaded the single unedited take where I show my unfamiliarity with recording myself. But there is a bit of footage of the game in there.

Here is the code from the video above, which I am open to criticism: Untitled - TextBin

I’ll try to do an update here when some significant developments happens. I would like to improve at showing my project in videos and in code, as I feel like I’m learning a lot of the pitfalls of making a larger game with Defold on my own and without realizing I’m in a pit fall until I’m quite deep into it.

6 Likes

I like the game, it gives the cozy game feeling well :slight_smile:

(Hitting chickens to get egg was not something I was expecting though :sweat_smile: )

1 Like

How did you do collisions? Those red green blue lines are raycast?

1 Like

A couple people have told me that it’s disturbing, which was not completely intentional. I think the asset bundle screams “cozy farm game” but then you get into it and it’s irreverent, absurdity which defies peoples’ expectations.

It’s a combination of the standardcontact_point_responsesolution that’s in the docs for handling solid collisions and those raycasts that I added to deal with edge cases. Now that you mention it I should probably go back and see how many of thecontact_point_response handlers are still needed after adding the raycasts.

This is the part I’m assuming you want to see. Here are the horizontal raycasts but also have vertical ones too.


if original_velocity.x ~= 0 then
    local horizontal_dir = vmath.normalize(vmath.vector3(original_velocity.x, 0, 0))
    local right = vmath.vector3(0, 1, 0)
    local left = vmath.vector3(0, -1, 0)
    local middle = vmath.vector3()

    local start_pos_right = pos + right * offset_distance
    local start_pos_left = pos + left * offset_distance
    local start_pos_middle = pos + middle

    local end_pos_right = start_pos_right + horizontal_dir * (math.abs(original_velocity.x) * dt + buffer)
    local end_pos_left = start_pos_left + horizontal_dir * (math.abs(original_velocity.x) * dt + buffer)
    local end_pos_middle = start_pos_middle + horizontal_dir * (math.abs(original_velocity.x) * dt + buffer)

    local hit_right = physics.raycast(start_pos_right, end_pos_right, collision_mask)
    local hit_left = physics.raycast(start_pos_left, end_pos_left, collision_mask)
    local hit_middle = physics.raycast(start_pos_middle, end_pos_middle, collision_mask)

    -- msg.post("@render:", "draw_line", { start_point = start_pos_right, end_point = end_pos_right, color = vmath.vector4(1, 0, 0, 1) }) -- Red
    -- msg.post("@render:", "draw_line", { start_point = start_pos_left, end_point = end_pos_left, color = vmath.vector4(0, 1, 0, 1) }) -- Green
    -- msg.post("@render:", "draw_line", { start_point = start_pos_middle, end_point = end_pos_middle, color = vmath.vector4(0, 0, 1, 1) }) -- Blue

    if hit_right or hit_left or hit_middle then
        velocity.x = 0
    end

    -- Push through single tile gap
    local horizontal_dir = vmath.normalize(vmath.vector3(original_velocity.x, 0, 0))
    local function can_move_in_direction(direction)
        local check_start = pos + horizontal_dir * buffer
        local check_end = check_start + direction * offset_distance
        local hit = physics.raycast(check_start, check_end, collision_mask)
        -- msg.post("@render:", "draw_line", { start_point = check_start, end_point = check_end, color = vmath.vector4(0, 1, 1, 1) })
        return not hit
    end

    if hit_right and not hit_left then
        if can_move_in_direction(left) then
            is_colliding_toward_opening = true
            velocity.y = velocity.y - ((is_knockback or is_dodging) and original_velocity.y or self.speed)    
        end
    elseif hit_left and not hit_right then
        if can_move_in_direction(right) then
            is_colliding_toward_opening = true
            velocity.y = velocity.y + ((is_knockback or is_dodging) and original_velocity.y or self.speed) 
        end
    end
end

IMO that last bit is the most interesting. For each direction there are three casts. If an outer most cast is the only one that lands on a solid, it infers that the player is possibly trying to move into a one tile space. It will then do another cast in the direction that will allow the player to move through the opening and if that does not land, it will push the player towards the opening. This helps with letting the player walk through one tile spaces they would otherwise have to line up precisely and avoids the annoyance of getting stuck on corners easily.

1 Like

You have a really good video presentation style and blog post, I hope you keep finding time to work on it, I think you could be really successful with it.

1 Like

Thanks. Blogging in a lot of ways is pretty outdated in terms of reaching an audience but putting all those clips together and writing about it helped motivate me to start working on it again.

That seems to be my cycle is I put a lot of work into the game and then I get really burnt out on it. So I then switch to sharing what I worked on and it sometimes redirects energy back into wanting to work again.

1 Like