Giter Site home page Giter Site logo

platypus's Introduction

Platypus

Defold platformer engine.

Setup

You can use the extension in your own project by adding this project as a Defold library dependency. Open your game.project file and in the dependencies field under project add:

https://github.com/britzl/Platypus/archive/master.zip

Or point to the ZIP file of a specific release.

Example

See an example of Platypus in action by running the grottoescape.collection of this project or try the HTML5 demo.

Usage

Creating an instance

Use platypus.create() to create a Platypus instance. Use this to control a single game object. Each frame you need to call platypus.update() and platypus.on_message().

function init(self)
	self.platypus = platypus.create(config)
end

function update(self, dt)
	self.platypus.update(dt)
end

function on_message(self, message_id, message, sender)
	self.platypus.on_message(message_id, message)
end

Player movement

Use platypus.left(), platypus.right(), platypus.up(), platypus.down() and platypus.move() to move the player. The movement will happen during the next call to platypus.update().

function init(self)
	self.platypus = platypus.create(config)
end

function update(self, dt)
	self.platypus.update(dt)
end

function on_message(self, message_id, message, sender)
	self.platypus.on_message(message_id, message)
end

function on_input(self, action_id, action)
	if action_id == hash("left") then
		self.platypus.left(250)
	elseif action_id == hash("right") then
		self.platypus.right(250)
	end
end

Jumping

Platypus supports normal jumps when standing on the ground, wall jumps when in contact with a wall in the air and double jumps. You can also perform a "forced" jump that will perform a jump regardless of state. This can be useful when implementing rope mechanics and other such functions where there is no ground or wall contact.

Use platypus.jump() to perform a jump and platypus.abort_jump() to reduce the height of a jump that is already in progress.

function init(self)
	self.platypus = platypus.create(config)
end

function update(self, dt)
	self.platypus.update(dt)
end

function on_message(self, message_id, message, sender)
	self.platypus.on_message(message_id, message)
end

function on_input(self, action_id, action)
	if action_id == hash("jump") then
		if action.pressed then
			self.platypus.jump(800)
		elseif action.released then
			self.platypus.abort_jump(0.5)
		end
	end
end

Double jump, wall jump and wall slide

Platypus supports double jumps when config.allow_double_jump is set to true. A double jump is performed automatically when a second jump is done before and up until reaching the apex of the first jump. It is not possible to perform a double jump when falling

Platypus supports wall jumps when config.allow_wall_jump is set to true. A wall jump is performed automatically when jumping while having wall contact while falling or wall sliding. The wall jump pushes the player out from the wall in question. Normally, user can alter your movement right after bounced from a wall, but when you set config.const_wall_jump - the bounce will be always the same and user won't be able to alter it.

Platypus supports wall slide when config.allow_wall_slide is set to true. A wall slide will be performed automatically when the player has wall contact while falling and moving (using platypus.left() or platypus.right()) in the direction of the wall. Platypus offers also to abort_wall_slide(), for example, when the control key is released, so user is no longer pushing toward the wall.

Collision detection

Platypus uses ray casts to detect collisions (configured when creating a Platypus instance).

State changes

Platypus will send messages for certain state changes so that scripts can react, for instance by changing animation.

function init(self)
	self.platypus = platypus.create(config)
end

function update(self, dt)
	self.platypus.update(dt)
end

function on_message(self, message_id, message, sender)
	self.platypus.on_message(message_id, message)
	if message_id == platypus.FALLING then
		print("I'm falling")
	elseif message_id == platypus.GROUND_CONTACT then
		print("Phew! Solid ground")
	elseif message_id == platypus.WALL_CONTACT then
		print("Ouch!")
	elseif message_id == platypus.WALL_JUMP then
		print("Doing a wall jump!")
	elseif message_id == platypus.DOUBLE_JUMP then
		print("Doing a double jump!")
	elseif message_id == platypus.JUMP then
		print("Jumping!")
    elseif message_id == platypus.WALL_SLIDE then
		print("Sliding down a wall!")
	end
end

Platypus API

Functions

platypus.create(config)

Create an instance of Platypus. This will provide all the functionality to control a game object in a platformer game. The functions will operate on the game object attached to the script calling the functions.

PARAMETERS

  • config (table) - Table with configuration values

The config table can have the following values:

  • collisions (table) - Lists of collision groups and bounding box size (REQUIRED)
  • debug (boolean) - True to draw ray casts
  • reparent (boolean) - True if the Platypus game object should be reparented when having ground contact. This is useful when having horizontally moving platforms. Defaults to true. (OPTIONAL)
  • gravity (number) - Gravity (pixels/s) (OPTIONAL)
  • max_velocity (number) - Maximum velocity of the game object (pixels/s). Set this to limit speed and prevent full penetration of game object into level geometry (OPTIONAL)
  • wall_jump_power_ratio_x (number) - Amount to multiply the jump power with when applying horizontal velocity during a wall jump (OPTIONAL)
  • wall_jump_power_ratio_y (number) - Amount to multiply the jump power with when applying vertical velocity during a wall jump (OPTIONAL)
  • allow_double_jump (boolean) - If double jumps are allowed (OPTIONAL)
  • allow_wall_jump (boolean) - If wall jumps are allowed (OPTIONAL)
  • const_wall_jump (boolean) - If true - prevents user from changing velocity while bounced from a wall. Set to false by default, to keep legacy behavior. (OPTIONAL)
  • allow_wall_slide (boolean) - If true - wall slide is allowed (by pushing forward on a wall while falling) (OPTIONAL)
  • wall_slide_velocity (number) - "gravity" that applies when sliding down the wall (generally should be lower than overall gravity, to simulate sliding) (OPTIONAL)

The collisions table can have the following values:

  • groups (table) - List with collision groups. Used when separating collisions.
  • left (number) - Distance from game object center to left edge of collision area. Used by ray casts to detect ground and wall contact and when separating collisions using rays.
  • right (number) - Distance from game object center to right edge of collision area. Used by ray casts to detect ground and wall contact and when separating collisions using rays.
  • top (number) - Distance from game object center to top edge of collision area. Used by ray casts to detect ground and wall contact and when separating collisions using rays.
  • bottom (number) - Distance from game object center to bottom edge of collision area. Used by ray casts to detect ground and wall contact and when separating collisions using rays.
  • offset (vector3) - Offset from the game object center to the center of the collision area. Use this when your sprite and collision area isn't centered around the game object center. Defaults to (0, 0, 0).

The groups table should map collision group hashes as keys to which collision directions to detect collisions with:

{
	[hash("ground")] = platypus.DIR_ALL,
	[hash("onewayplatform")] = platypus.DIR_DOWN,
	[hash("onewaydoor")] = platypus.DIR_LEFT,
}

RETURN

  • instance (table) - The created Platypus instance

The instance table has all of the instance functions describe below in addition to the values from config (either provided values or defaults) and the following fields:

  • velocity - The current velocity of the game object

You can modify any of the instance values at runtime to change the behavior of the platypus instance.

instance.update(dt)

Update the Platypus instance. This will move the game object and send out state changes.

PARAMETERS

  • dt (number) - Delta time

instance.on_message(message_id, message)

Forward received messages from the on_message lifecycle function to this instance function. This will handle collision messages and custom messages generated by the Platypus instance itself

PARAMETERS

  • message_id (hash) - Id of the received message
  • message (table) - The message data

instance.left(velocity)

Move the game object to the left during next update. This will override any previous call to instance.left() or instance.right() as well as the horizontal velocity of instance.move().

PARAMETERS

  • velocity (number) - Amount to move left (pixels/s)

instance.right(velocity)

Move the game object to the right during next update. This will override any previous call to instance.left() or instance.right() as well as the horizontal velocity of instance.move().

PARAMETERS

  • velocity (number) - Amount to move right (pixels/s)

instance.up(velocity)

Move the game object up during next update. This will override any previous call to instance.up() or instance.down() as well as the vertical velocity of instance.move().

PARAMETERS

  • velocity (number) - Amount to move up (pixels/s)

instance.down(velocity)

Move the game object down during next update. This will override any previous call to instance.up() or instance.down() as well as the vertical velocity of instance.move().

PARAMETERS

  • velocity (number) - Amount to move down (pixels/s)

instance.move(velocity)

Move the game object during next update. This will override any previous call to instance.left(), instance.right(), instance.up(), instance.down() and instance.move().

PARAMETERS

  • velocity (vector3) - Amount to move (pixels/s)

instance.jump(power)

Make the game object perform a jump. Depending on state and configuration, this can either be a normal jump from standing on the ground, a wall jump if having wall contact and no ground contact, or a double jump if jumping up and not falling down.

PARAMETERS

  • power (number) - Initial takeoff speed (pixels/s)

instance.force_jump(power)

Make the game object perform a jump, regardless of current state.

PARAMETERS

  • power (number) - Initial takeoff speed (pixels/s)

instance.abort_jump(reduction)

Abort a jump by "cutting it short". This will reduce the vertical speed by some fraction.

PARAMETERS

  • reduction (number) - Amount to multiply vertical velocity with

instance.abort_wall_slide()

Abort a slide down a wall (could be used when releasing the pushing control key)

instance.has_ground_contact()

Check if the game object is standing on the ground

RETURN

  • ground_contact (boolean) - True if standing on the ground

instance.has_wall_contact()

Check if the game object is in contact with a wall

RETURN

  • wall_contact (boolean) - True if in contact with a wall

instance.is_falling()

Check if the game object is falling. The game object is considered falling if not having ground contact and velocity is pointing down.

RETURN

  • falling (boolean) - True if falling

instance.is_jumping()

Check if the game object is jumping. The game object is considered falling if not having ground contact and velocity is pointing up.

RETURN

  • jumping (boolean) - True if jumping

instance.is_wall_jumping()

Check if the game object is jumping after a bounce from a wall. The game object is considered falling if not having ground contact and velocity is pointing up.

RETURN

  • wall_jump (boolean) - True if jumping after a bounce from a wall.

instance.is_wall_sliding()

Check if the game object is sliding down a wall.

RETURN

  • wall_slide (boolean) - True if sliding down a wall.

instance.toggle_debug()

Toggle debug draw of ray casts.

instance.set_collisions(collisions)

Change the rays and bounds for collision detection.

PARAMETERS

  • collisions (table) - collisions table with top,left,right and bottom keys

Messages

platypus.FALLING

Sent once when the game object starts to fall

platypus.GROUND_CONTACT

Sent once when the game object detects ground contact

platypus.WALL_CONTACT

Sent once when the game object detects wall contact

platypus.JUMP

Sent when the game object jumps

platypus.WALL_JUMP

Sent when the game object performs a wall jump

platypus.DOUBLE_JUMP

Sent when the game object performs a double jump

platypus.WALL_SLIDE

Sent when the game object starts sliding down a wall

Credits

platypus's People

Contributors

britzl avatar jeangit avatar megus avatar paweljarosz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

platypus's Issues

Add support for one way platforms

Perhaps add a way to configure collision groups so that they will ignore collisions in certain directions.

platypus.UP = x01
platypus.LEFT = x02
platypus.RIGHT = x04
platypus.DOWN = x08

platypus.create({
	collisions = {
		ground = {
			[hash("ground")] = platypus.UP + platypus.LEFT + platypus.RIGHT + platypus.DOWN,
			[hash("onewayplatform")] = platypus.LEFT + platypus.RIGHT + platypus.DOWN,
		}
	}
})

The config decides how to deal with contact_point_response and ray_cast_response messages.

Change config values at runtime

Expose the config options so they’re changable in real time (edit: probably could also do this by nil’ing the existing instance and creating a new one but on the fly changes would be easier)

onewayplatform (weird behavior) gets stuck at groundcontact

RECORDING

I was messing aroung with onewayplatforms but it seems I can't jump past them, I'm using the example code from the repo, this is the platypus.config

self.platypus = platypus.create({
    collisions = {
        separation = platypus.SEPARATION_SHAPES,
        groups = {
            [hash("ground")] = platypus.DIR_ALL,
            [hash("onewayplatform")] = platypus.DIR_DOWN,
            [hash("onewaydoor")] = platypus.DIR_LEFT,
        },
        left = 22.5, right = 22.5, top = 21.5, bottom = 23.5, offset = vmath.vector3(0, -4, 0)
    },
    gravity = -800,
    max_velocity = 580,
    allow_double_jump = true,
    allow_wall_jump = true,
    allow_wall_slide = true,
    wall_slide_gravity = -50,
})

Player stays parented to moving platform after jumping off

Can be replicated using HTML5 demo on github page.

When player jumps off a moving platform, the player object is still parented to the platform until it collides with another object. This causes the player to move in relation to the platform in mid air.

Can be tested by standing on a moving platform and simply jumping without moving. Player will follow platforms movement.

Inconsistent collision detection

With moving platforms, collision detection can be very inconsistent, resulting the character moving into platforms and being warped out of platforms when collision is detected too late.

go1
go2

I played around with adding more rays, but that does only help a little:
g1
g2

Adding even more rays in between, the character get's caught up on platforms even easier.

Vertical moving platform and player seperation

Player 'Leaves' vertical platform on way down even though gravity is set to a sufficient level as to keep player grounded on the platform.

To recreate:
In the example project set the Duration in moving_platform_3 to 2.5 then jump on it.

Player movement anomolies when dropping between moving platform and wall

If a player drops between a collision involving a wall/static platform and a moving platform (for example when a moving platform bridges two static platforms by moving side to side) player movement anomalies occur.

Observed anomalies:

  • In some cases the player gets "absorbed" into the moving platform and moves with it while inside
  • General player "judder" movments

Possible workaround:

  • When creating an instance add a "moving_ground" table to identify moving platform collision group hashes
  • Temporarily disable an active collision with a "moving_ground" object if hit from the side to let the player drop through

Unable to change length of collision RAYCAST at runtime

The Cyber Platypus issue report.zip

I am trying to create Crouch mechanism which requires changing Collision Raycast length at runtime
But when i manually change is_crouching variable ( true or false) and then run the game everything works fine ( raycast's length is as expected)
BUT when i try to change this from player script at runtime ( on input : Crouch) , the crouch state in platypus.lua changes well while the actual Raycast's length donot .

Seems like the platypus script decides the Raycast's length at initializing only .

i made following changes to platypus.lua for this mechanism :

Declared variable for storing Crouching state at LINE 10:

Screenshot 2023-11-23 091056

parameter for length of raycast during crouching state :

Screenshot 2023-11-23 091159

using the crouch state to decide when to use which length :

Screenshot 2023-11-23 091248

List of potential feature improvements

  • Hang on edge of platforms / wall nooks / pegs
  • run
  • double jump (or as many extra jumps)
  • downward slam
  • upward super jump (rook)
  • spiderman style rope swing / hook shot swing
  • look up / down when holding up or down move camera up or down
  • couch to avoid bullets aimed and player head
  • crawl to crawl under short areas
  • slide to slide under short areas
  • wall hold slide down
  • jump down from one way platformers by holding down and jump
  • horizontal dash
  • dash to break breakables
  • jetpack
  • ropes
  • swim
  • free fly
  • different gravity zones
  • swap vertical gravity
  • portals
  • doors
  • pushable blocks
  • camera shake (want to use noise so it’s smooth I have examples somewhere…)
  • micro freeze frame when taking damage / doing damage
  • basic enemy AI following player and is willing to fall off platforms / will try to jump to nearby platforms if it can / free fly ai that chases player / ai which walks between paths
  • slopes (you need a custom pill shape for this to work right)
  • parallax systems for background layers
  • jumping bounce pads
  • windy areas
  • icy floors that are slippery
  • keys / doors / switches
  • collectibles

Player hops up when ground is removed from underneath them

This forum post provides some deeper information including a video example.

The code causing this is on platypus.lua:473-481:

-- was the ground we're standing on removed?
if platypus.parent_id then
    local ok, _ = pcall(go.get_position, platypus.parent_id)
    if not ok then
        platypus.parent_id = nil
    	state.current.ground_contact = false
    	go.set_position(go.get_position() + state.current.world_position - state.current.position)
    end
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.