Based on freelancer jekyll theme here.
For more details, read the documentation
agsbox2d is a Box2D plugin for Adventure Game Studio
Home Page: https://www.adventuregamestudio.co.uk/forums/index.php?topic=57458.0
License: Other
Based on freelancer jekyll theme here.
For more details, read the documentation
For now, when the pointer of a Box2D thing goes out of scope, things can break. Specifically, the world should never go out of scope or the things it contains will go kaboom. Instead we need to properly invalidate all the pointers - passing null to previously contained AgsBody objects.
Right now the project expects AGS is cloned to a ../ags
directory, but this isn't mentioned in the README.
I imagine if there's some way to reasonably fast package the non walkable pixels into boxes (static bodies with rectangle shape) then we could have a function that loads the walkable areas into the world.
https://stackoverflow.com/questions/57745418/pack-pixels-in-1bit-bw-binary-image-in-boxes/
Other idea is Moore Neighbor tracing
Potrace may be useful.
Also XAGE has a similar converter to polygons for walkable areas on AGS Export plug-in
ags stores everything as ints, so if you just pass float to function, it will be converted to int loosing its float quality.
Like if you pass 1.5 it will become 1
so instead you must cheat to make receiving function think that this is integer.
something like:
union
{
float f;
uint32_t ui32;
} hack;
hack.f = 123.456;
CallEngine(hack.ui32);
here union is 4 bytes, and it can be seen as both float and uint32. So you can assign it as float and pass as integer, and all data will stay as it is necessary for float.
internally engine does opposite conversion.
Just add a reminder of the license used similar to:
/*
* Copyright (C) <Year> <Name of Author>
*
* This program is free software. You can use and redistribute it
* under the terms and conditions of the zlib-license (see LICENCE).
*
* SPDX-License-Identifier: Zlib
*/
Need both b2fixture ID as in AGS Script FixtureID and b2body ID as in AGS Script ID - so they would not reflect their wrappers IDs, but the IDs of the Box2D elements they represent and give interface too. Theoretically, it should exist only one wrapper element ( AgsBody, AgsFixture) for one Box2D element (b2Body, b2Fixture), but I need IDs to test if this proceeds.
Created a first version of boxify module.
using tileset https://opengameart.org/content/spooky-castle-tileset , still need to add credit somewhere.
AgsBox2D : similar to love.physics
Body : similar to body from love
World - similar to world from love
Shape
Fixture : similar to fixture from love
Especially when displaying huge chunks of code on tiny monitors #endif
statements could
use some sort of comment stating what they end.
The only file that doesn't seem to come directly from Box2D (which apparently doesn't have any comments after #endif
statements) that is affected by this issue is agsbox2d.cpp
#if AGS_PLATFORM_OS_WINDOWS
//==============================================================================
// ***** Design time *****
IAGSEditor *editor; // Editor interface
const char *ourScriptHeader =
" \r\n"
"enum BodyType { \r\n"
" eBodyStatic=0, \r\n"
" eBodyKinematic=1, \r\n"
" eBodyDynamic=2, \r\n"
"}; \r\n"
" \r\n"
"managed struct Body { \r\n"
" import attribute float fX; \r\n"
" import attribute float fY; \r\n"
" import attribute int X; \r\n"
" import attribute int Y; \r\n"
" import attribute bool FixedRotation; \r\n"
" import attribute bool Bullet; \r\n"
" readonly import attribute bool IsDestroyed; \r\n"
" import attribute float Angle; \r\n"
" import attribute float LinearDamping; \r\n"
" import attribute float AngularDamping; \r\n"
" import attribute float AngularVelocity; \r\n"
" import attribute float Inertia; \r\n"
" readonly import attribute float LinearVelocityX; \r\n"
" readonly import attribute float LinearVelocityY; \r\n"
" import void ApplyForce(float fx, float fy); \r\n"
" import void SetLinearVelocity(float fx, float fy); \r\n"
" import void ApplyAngularImpulse(float impulse); \r\n"
" import void ApplyLinearImpulse(float intensity_x, float intensity_y); \r\n"
" import void ApplyTorque(float torque); \r\n"
" import bool IsTouching(Body* other); \r\n"
"}; \r\n"
" \r\n"
"managed struct World { \r\n"
" \r\n"
" /// Advances one step of the simulation \r\n"
" import void Step(float dt, int velocityIteractions = 8, int positionIteractions = 3); \r\n"
"}; \r\n"
" \r\n"
"managed struct ShapeCircle; \r\n"
"managed struct ShapeRectangle; \r\n"
" \r\n"
"managed struct Shape { \r\n"
" \r\n"
" /// If this shape is a circle, returns the ShapeCircle interface; otherwise null. \r\n"
" readonly import attribute ShapeCircle* AsCircle; // $AUTOCOMPLETENOINHERIT$ \r\n"
" \r\n"
" /// If this shape is a rectangle, returns the ShapeRectangle interface; otherwise null. \r\n"
" readonly import attribute ShapeRectangle* AsRectangle; // $AUTOCOMPLETENOINHERIT$ \r\n"
"}; \r\n"
" \r\n"
"managed struct ShapeCircle extends Shape { \r\n"
" \r\n"
"}; \r\n"
" \r\n"
"managed struct ShapeRectangle extends Shape { \r\n"
" \r\n"
" import attribute float fWidth; \r\n"
" import attribute float fHeight; \r\n"
" import attribute int Height; \r\n"
" import attribute int Width; \r\n"
" readonly import attribute float PointsfX[]; \r\n"
" readonly import attribute float PointsfY[]; \r\n"
" \r\n"
"}; \r\n"
" \r\n"
"managed struct Fixture { \r\n"
" import attribute float Friction; \r\n"
" import attribute float Density; \r\n"
" import attribute float Restitution; \r\n"
" \r\n"
"}; \r\n"
" \r\n"
"struct AgsBox2D { \r\n"
" \r\n"
" /// Set Meter \r\n"
" import static void SetMeter(float meter); \r\n"
" \r\n"
" /// Get Meter \r\n"
" import static float GetMeter(); \r\n"
" \r\n"
" /// Create World \r\n"
" import static World* CreateWorld(float gravityX, float gravityY); \r\n"
" \r\n"
" /// Create Body \r\n"
" import static Body* CreateBody(World* world, float x, float y, BodyType bodytype); \r\n"
" /// Destroy Body \r\n"
" import static void DestroyBody(World* world, Body* body); \r\n"
" \r\n"
" /// Create Rectangle Shape \r\n"
" import static Shape* CreateRectangleShape(float w, float h, float x=0, float y=0); \r\n"
" \r\n"
" /// Create Circle Shape \r\n"
" import static Shape* CreateCircleShape(float radius, float x=0, float y=0); \r\n"
" \r\n"
" /// Create Fixture \r\n"
" import static Fixture* CreateFixture(Body* body, Shape* shape, float density=0); \r\n"
" \r\n"
"}; \r\n";
//------------------------------------------------------------------------------
LPCSTR AGS_GetPluginName()
{
return ("agsbox2d");
}
//------------------------------------------------------------------------------
int AGS_EditorStartup(IAGSEditor *lpEditor)
{
// User has checked the plugin to use it in their game
// If it's an earlier version than what we need, abort.
if (lpEditor->version < MIN_EDITOR_VERSION)
return (-1);
editor = lpEditor;
editor->RegisterScriptHeader(ourScriptHeader);
// Return 0 to indicate success
return (0);
}
//------------------------------------------------------------------------------
void AGS_EditorShutdown()
{
// User has un-checked the plugin from their game
editor->UnregisterScriptHeader(ourScriptHeader);
}
//------------------------------------------------------------------------------
void AGS_EditorProperties(HWND parent) //*** optional ***
{
// User has chosen to view the Properties of the plugin
// We could load up an options dialog or something here instead
/* MessageBox(parent,
L"agsfastwfc v1.0 By Calin Leafshade",
L"About",
MB_OK | MB_ICONINFORMATION);
*/
}
//------------------------------------------------------------------------------
int AGS_EditorSaveGame(char *buffer, int bufsize) //*** optional ***
{
// Called by the editor when the current game is saved to disk.
// Plugin configuration can be stored in [buffer] (max [bufsize] bytes)
// Return the amount of bytes written in the buffer
return (0);
}
//------------------------------------------------------------------------------
void AGS_EditorLoadGame(char *buffer, int bufsize) //*** optional ***
{
// Called by the editor when a game is loaded from disk
// Previous written data can be read from [buffer] (size [bufsize]).
// Make a copy of the data, the buffer is freed after this function call.
}
//==============================================================================
#endif
Even though, Box2D.h etc. seem to be taken directly (or with some slight modifications) from Box2D I'd consider adding some comments. However, it certainly wouldn't make sense to "fix" a library that's updated frequently (nor would I want to update a 7000 lines file ๐ ).
"builtin
" means that user cannot create instances of that type in script using new
.
Lot's of things in this plug-in are produced by the AgsBox2D factory and itself too needs this keyword added.
Allow implement good controllers in a physics world
Provide some way to easily get a Room Object manipulated by a world. This is possible now through AGS Script but if some way to easen this can be created it would be useful.
Potentially it would allow specifying a margin with an eInnerMarging
specifier of inner margin or eOuterMargin. Not sure yet if outer margin would actually be useful. But it would be useful passing an innermarging, I assume also objects are created as rectangle boxes by default. Maybe adding an option to be a circle too.
My first guess is a contact stack that is read only and changes at each time step
I would also like to add some way to filter contacts with a fixture from this stack. And also, some way to pass an array of fixtures to ignore (which the contacts involving them aren't put on the array on first place).
Still, the callbacks approach is more interesting, but I am not sure how well it would work in AGS. Maybe need to branch and test this.
First, objects need to have IDs
To serialize objects they need to store their IDs and the IDs of any objects they point too: Bodies, their world ID; Fixtures, the IDs things the fixtures contains; And so on.
These IDs will be used for deserialization, since we can't store pointers because the memory will be different.
When an object is deserialized, it needs to check if it's own ID is on it's respective table pointer. If it isn't, we instantiate that object with the received parameters from deserialization process. If it's, we instead skip instantiation, and apply the parameters on the already instantiated object.
So when deserializing an object that points to other object, we get the ID of the object it points to (and we know the type of that ID). We check a table that has IDs as keys and the respective pointer as value. If that ID is found, we get the pointer and place in the right place. If that ID is not found, we initialize the object with default parameters anyway and place it on the table with the ID.
And try to do the same for pointers when possible/needed.
Checking if a fixture/body is asleep may be useful when selecting what I should move/update animation state, in a more complex/larger world.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.