Add custom gravity mode and replace hardcoded gravity interactions (#820)

Co-authored-by: Tamás Bálint Misius <lbphacker@gmail.com>
This commit is contained in:
catsoften 2022-07-31 02:19:16 -04:00 committed by GitHub
parent a0016a2b9c
commit 6aa68adbf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 485 additions and 95 deletions

View File

@ -26,6 +26,8 @@ GameSave::GameSave(const GameSave & save):
aheatEnable(save.aheatEnable),
paused(save.paused),
gravityMode(save.gravityMode),
customGravityX(save.customGravityX),
customGravityY(save.customGravityY),
airMode(save.airMode),
ambientAirTemp(save.ambientAirTemp),
edgeMode(save.edgeMode),
@ -174,6 +176,8 @@ void GameSave::InitVars()
aheatEnable = false;
paused = false;
gravityMode = 0;
customGravityX = 0.0f;
customGravityY = 0.0f;
airMode = 0;
ambientAirTemp = R_TEMP + 273.15f;
edgeMode = 0;
@ -702,6 +706,8 @@ void GameSave::readOPS(char * data, int dataLength)
CheckBsonFieldBool(iter, "waterEEnabled", &waterEEnabled);
CheckBsonFieldBool(iter, "paused", &paused);
CheckBsonFieldInt(iter, "gravityMode", &gravityMode);
CheckBsonFieldFloat(iter, "customGravityX", &customGravityX);
CheckBsonFieldFloat(iter, "customGravityY", &customGravityY);
CheckBsonFieldInt(iter, "airMode", &airMode);
CheckBsonFieldFloat(iter, "ambientAirTemp", &ambientAirTemp);
CheckBsonFieldInt(iter, "edgeMode", &edgeMode);
@ -2614,6 +2620,12 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
bson_append_string(&b, "platform", IDENT_PLATFORM);
bson_append_string(&b, "builtType", IDENT_BUILD);
bson_append_finish_object(&b);
if (gravityMode == 3)
{
bson_append_double(&b, "customGravityX", double(customGravityX));
bson_append_double(&b, "customGravityY", double(customGravityY));
RESTRICTVERSION(97, 0);
}
bson_append_start_object(&b, "minimumVersion");
bson_append_int(&b, "major", minimumMajorVersion);
bson_append_int(&b, "minor", minimumMinorVersion);

View File

@ -95,6 +95,8 @@ public:
bool aheatEnable;
bool paused;
int gravityMode;
float customGravityX;
float customGravityY;
int airMode;
float ambientAirTemp;
int edgeMode;

View File

@ -809,7 +809,7 @@ void GameController::ResetSpark()
void GameController::SwitchGravity()
{
gameModel->GetSimulation()->gravityMode = (gameModel->GetSimulation()->gravityMode+1)%3;
gameModel->GetSimulation()->gravityMode = (gameModel->GetSimulation()->gravityMode+1)%4;
switch (gameModel->GetSimulation()->gravityMode)
{
@ -822,6 +822,9 @@ void GameController::SwitchGravity()
case 2:
gameModel->SetInfoTip("Gravity: Radial");
break;
case 3:
gameModel->SetInfoTip("Gravity: Custom");
break;
}
}

View File

@ -954,6 +954,8 @@ void GameModel::SetSave(SaveInfo * newSave, bool invertIncludePressure)
GameSave * saveData = currentSave->GetGameSave();
SetPaused(saveData->paused | GetPaused());
sim->gravityMode = saveData->gravityMode;
sim->customGravityX = saveData->customGravityX;
sim->customGravityY = saveData->customGravityY;
sim->air->airMode = saveData->airMode;
sim->air->ambientAirTemp = saveData->ambientAirTemp;
sim->edgeMode = saveData->edgeMode;
@ -1016,6 +1018,8 @@ void GameModel::SetSaveFile(SaveFile * newSave, bool invertIncludePressure)
GameSave * saveData = newSave->GetGameSave();
SetPaused(saveData->paused | GetPaused());
sim->gravityMode = saveData->gravityMode;
sim->customGravityX = saveData->customGravityX;
sim->customGravityY = saveData->customGravityY;
sim->air->airMode = saveData->airMode;
sim->air->ambientAirTemp = saveData->ambientAirTemp;
sim->edgeMode = saveData->edgeMode;
@ -1329,6 +1333,8 @@ void GameModel::ClearSimulation()
{
//Load defaults
sim->gravityMode = 0;
sim->customGravityX = 0.0f;
sim->customGravityY = 0.0f;
sim->air->airMode = 0;
sim->legacy_enable = false;
sim->water_equal_test = false;

View File

@ -0,0 +1,150 @@
#include "DirectionSelector.h"
namespace ui {
DirectionSelector::DirectionSelector(ui::Point position, float radius):
ui::Component(position, ui::Point(radius * 2, radius * 2)),
radius(radius),
maxRadius(radius - (radius / 4)),
useSnapPoints(false),
snapPointRadius(0),
snapPoints(std::vector<ui::Point>()),
autoReturn(false),
backgroundColor(ui::Colour(0, 0, 0, 63)),
foregroundColor(ui::Colour(63, 63, 63, 127)),
borderColor(ui::Colour(255, 255, 255)),
snapPointColor(ui::Colour(63, 63, 63, 127)),
updateCallback(nullptr),
changeCallback(nullptr),
mouseDown(false),
mouseHover(false),
altDown(false),
offset(ui::Point(0, 0))
{
}
void DirectionSelector::CheckHovering(int x, int y)
{
mouseHover = std::hypot((offset.X + radius) - x, (offset.Y + radius) - y) < radius / 4;
}
void DirectionSelector::SetSnapPoints(int newRadius, int points)
{
snapPointRadius = newRadius;
snapPoints.clear();
snapPoints.push_back(ui::Point(0, 0));
for (int i = 1; i < points; i++)
{
int dist = ((float)i / (float)(points - 1)) * maxRadius;
snapPoints.push_back(ui::Point(0, dist));
snapPoints.push_back(ui::Point(0, -1 * dist));
snapPoints.push_back(ui::Point(-1 * dist, 0));
snapPoints.push_back(ui::Point(dist, 0));
}
useSnapPoints = true;
}
void DirectionSelector::ClearSnapPoints()
{
useSnapPoints = false;
snapPoints.clear();
}
float DirectionSelector::GetXValue()
{
return offset.X / maxRadius;
}
float DirectionSelector::GetYValue()
{
return offset.Y / maxRadius;
}
float DirectionSelector::GetTotalValue()
{
return std::hypot(offset.X, offset.Y) / maxRadius;
}
void DirectionSelector::SetPositionAbs(float absx, float absy)
{
SetPosition(absx - radius, absy - radius);
}
void DirectionSelector::SetPosition(float x, float y)
{
if (std::hypot(x, y) > maxRadius)
{
offset.X = (maxRadius * x) / std::hypot(x, y);
offset.Y = (maxRadius * y) / std::hypot(x, y);
}
else
{
offset.X = x;
offset.Y = y;
}
if (useSnapPoints && !altDown)
{
for (const ui::Point& i : snapPoints)
if (std::hypot(i.X - offset.X, i.Y - offset.Y) <= snapPointRadius)
{
offset.X = i.X;
offset.Y = i.Y;
}
}
if (updateCallback)
updateCallback(GetXValue(), GetYValue());
}
void DirectionSelector::SetValues(float x, float y)
{
SetPosition(x * maxRadius, y * maxRadius);
}
void DirectionSelector::Draw(const ui::Point& screenPos)
{
Graphics * g = GetGraphics();
ui::Point center = screenPos + radius;
g->fillcircle(center.X, center.Y, radius, radius, backgroundColor.Red, backgroundColor.Green, backgroundColor.Blue, backgroundColor.Alpha);
g->drawcircle(center.X, center.Y, radius, radius, borderColor.Red, borderColor.Green, borderColor.Blue, borderColor.Alpha);
for (const ui::Point& i : snapPoints)
g->fillrect(
(center.X + i.X) - (radius / 30),
(center.Y + i.Y) - (radius / 30),
radius / 10, radius / 10,
snapPointColor.Red, snapPointColor.Green, snapPointColor.Blue, altDown ? (int)(snapPointColor.Alpha / 2) : snapPointColor.Alpha
);
g->fillcircle(center.X + offset.X, center.Y + offset.Y, radius / 4, radius / 4, foregroundColor.Red, foregroundColor.Green, foregroundColor.Blue, mouseHover ? std::min((int)(foregroundColor.Alpha * 1.5f), 255) : foregroundColor.Alpha);
g->drawcircle(center.X + offset.X, center.Y + offset.Y, radius / 4, radius / 4, borderColor.Red, borderColor.Green, borderColor.Blue, borderColor.Alpha);
}
void DirectionSelector::OnMouseMoved(int x, int y, int dx, int dy)
{
if (mouseDown)
SetPositionAbs(x, y);
CheckHovering(x, y);
}
void DirectionSelector::OnMouseClick(int x, int y, unsigned button)
{
mouseDown = true;
SetPositionAbs(x, y);
CheckHovering(x, y);
}
void DirectionSelector::OnMouseUp(int x, int y, unsigned button)
{
mouseDown = false;
if (autoReturn)
SetPosition(0, 0);
CheckHovering(x - Position.X, y - Position.Y);
if (changeCallback)
changeCallback(GetXValue(), GetYValue());
}
}

View File

@ -0,0 +1,86 @@
#ifndef DIRECTIONSELECTOR_H_
#define DIRECTIONSELECTOR_H_
#include "Component.h"
#include "Colour.h"
#include "graphics/Graphics.h"
#include <iostream>
#include <cmath>
#include <vector>
#include <functional>
namespace ui {
class DirectionSelector : public ui::Component
{
const float radius;
const float maxRadius;
bool useSnapPoints;
int snapPointRadius;
std::vector<ui::Point> snapPoints;
bool autoReturn;
ui::Colour backgroundColor;
ui::Colour foregroundColor;
ui::Colour borderColor;
ui::Colour snapPointColor;
public:
using DirectionSelectorCallback = std::function<void(float x, float y)>;
private:
DirectionSelectorCallback updateCallback;
DirectionSelectorCallback changeCallback;
bool mouseDown;
bool mouseHover;
bool altDown;
ui::Point offset;
void CheckHovering(int x, int y);
public:
DirectionSelector(ui::Point position, float radius);
virtual ~DirectionSelector() = default;
void SetSnapPoints(int newRadius, int points);
void ClearSnapPoints();
inline void EnableSnapPoints() { useSnapPoints = true; }
inline void DisableSnapPoints() { useSnapPoints = false; }
inline void EnableAutoReturn() { autoReturn = true; }
inline void DisableAutoReturn() { autoReturn = false; }
inline void SetBackgroundColor(ui::Colour color) { backgroundColor = color; }
inline void SetForegroundColor(ui::Colour color) { foregroundColor = color; }
inline void SetBorderColor(ui::Colour color) { borderColor = color; }
inline void SetSnapPointColor(ui::Colour color) { snapPointColor = color; }
float GetXValue();
float GetYValue();
float GetTotalValue();
void SetPositionAbs(float absx, float absy);
void SetPosition(float x, float y);
void SetValues(float x, float y);
void Draw(const ui::Point& screenPos) override;
void OnMouseMoved(int x, int y, int dx, int dy) override;
void OnMouseClick(int x, int y, unsigned int button) override;
void OnMouseUp(int x, int y, unsigned button) override;
inline void OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override { altDown = alt; }
inline void OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) override { altDown = alt; }
inline void SetUpdateCallback(DirectionSelectorCallback callback) { updateCallback = callback; }
inline void SetChangeCallback(DirectionSelectorCallback callback) { changeCallback = callback; }
};
} /* namespace ui */
#endif /* DIRECTIONSELECTOR_H_ */

View File

@ -5,6 +5,7 @@ gui_files += files(
'Component.cpp',
'ContextMenu.cpp',
'CopyTextButton.cpp',
'DirectionSelector.cpp',
'DropDown.cpp',
'Engine.cpp',
'Label.cpp',

View File

@ -42,6 +42,16 @@ void OptionsController::SetGravityMode(int gravityMode)
model->SetGravityMode(gravityMode);
}
void OptionsController::SetCustomGravityX(float x)
{
model->SetCustomGravityX(x);
}
void OptionsController::SetCustomGravityY(float y)
{
model->SetCustomGravityY(y);
}
void OptionsController::SetAirMode(int airMode)
{
model->SetAirMode(airMode);

View File

@ -21,6 +21,8 @@ public:
void SetNewtonianGravity(bool state);
void SetWaterEqualisation(bool state);
void SetGravityMode(int gravityMode);
void SetCustomGravityX(float x);
void SetCustomGravityY(float y);
void SetAirMode(int airMode);
void SetAmbientAirTemperature(float ambientAirTemp);
void SetEdgeMode(int edgeMode);

View File

@ -111,6 +111,28 @@ void OptionsModel::SetGravityMode(int gravityMode)
notifySettingsChanged();
}
float OptionsModel::GetCustomGravityX()
{
return sim->customGravityX;
}
void OptionsModel::SetCustomGravityX(float x)
{
sim->customGravityX = x;
notifySettingsChanged();
}
float OptionsModel::GetCustomGravityY()
{
return sim->customGravityY;
}
void OptionsModel::SetCustomGravityY(float y)
{
sim->customGravityY = y;
notifySettingsChanged();
}
int OptionsModel::GetScale()
{
return ui::Engine::Ref().GetScale();

View File

@ -34,6 +34,10 @@ public:
void SetEdgeMode(int edgeMode);
int GetGravityMode();
void SetGravityMode(int gravityMode);
float GetCustomGravityX();
void SetCustomGravityX(float x);
float GetCustomGravityY();
void SetCustomGravityY(float y);
int GetScale();
void SetScale(int scale);
bool GetResizable();

View File

@ -2,6 +2,7 @@
#include <cstdio>
#include <cstring>
#include <cmath>
#include "SDLCompat.h"
#include "OptionsController.h"
@ -21,6 +22,7 @@
#include "gui/interface/Engine.h"
#include "gui/interface/Label.h"
#include "gui/interface/Textbox.h"
#include "gui/interface/DirectionSelector.h"
OptionsView::OptionsView():
ui::Window(ui::Point(-1, -1), ui::Point(320, 340))
@ -143,7 +145,82 @@ OptionsView::OptionsView():
gravityMode->AddOption(std::pair<String, int>("Vertical", 0));
gravityMode->AddOption(std::pair<String, int>("Off", 1));
gravityMode->AddOption(std::pair<String, int>("Radial", 2));
gravityMode->SetActionCallback({ [this] { c->SetGravityMode(gravityMode->GetOption().second); } });
gravityMode->AddOption(std::pair<String, int>("Custom", 3));
class GravityWindow : public ui::Window
{
void OnTryExit(ExitMethod method)
{
CloseActiveWindow();
SelfDestruct();
}
void OnDraw()
{
Graphics * g = GetGraphics();
g->clearrect(Position.X-2, Position.Y-2, Size.X+3, Size.Y+3);
g->drawrect(Position.X, Position.Y, Size.X, Size.Y, 200, 200, 200, 255);
}
ui::DirectionSelector * gravityDirection;
ui::Label * labelValues;
OptionsController * c;
public:
GravityWindow(ui::Point position, int radius, float x, float y, OptionsController * c_):
ui::Window(position, ui::Point((radius * 2) + 20, (radius * 2) + 75)),
gravityDirection(new ui::DirectionSelector(ui::Point(10, 32), radius)),
c(c_)
{
ui::Label * tempLabel = new ui::Label(ui::Point(4, 1), ui::Point(Size.X - 8, 22), "Custom Gravity");
tempLabel->SetTextColour(style::Colour::InformationTitle);
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
tempLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(tempLabel);
Separator * tempSeparator = new Separator(ui::Point(0, 22), ui::Point(Size.X, 1));
AddComponent(tempSeparator);
labelValues = new ui::Label(ui::Point(0, (radius * 2) + 37), ui::Point(Size.X, 16), String::Build( "X:", std::round(x * 10.0f) / 10,
" Y:", std::round(y * 10.0f) / 10,
" Total:", std::round(std::hypot(x, y) * 10.0f) / 10));
labelValues->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
labelValues->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
AddComponent(labelValues);
gravityDirection->SetValues(x / 2.0f, y / 2.0f);
gravityDirection->SetUpdateCallback([this](float x, float y) {
labelValues->SetText(String::Build( "X:", std::round(x * 20.0f) / 10,
" Y:", std::round(y * 20.0f) / 10,
" Total:", std::round(gravityDirection->GetTotalValue() * 20.0f) / 10));
});
gravityDirection->SetSnapPoints(5, 5);
AddComponent(gravityDirection);
ui::Button * okayButton = new ui::Button(ui::Point(0, Size.Y - 17), ui::Point(Size.X, 17), "OK");
okayButton->Appearance.HorizontalAlign = ui::Appearance::AlignCentre;
okayButton->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
okayButton->Appearance.BorderInactive = ui::Colour(200, 200, 200);
okayButton->SetActionCallback({ [this] {
c->SetCustomGravityX(gravityDirection->GetXValue() * 2.0f);
c->SetCustomGravityY(gravityDirection->GetYValue() * 2.0f);
CloseActiveWindow();
SelfDestruct();
} });
AddComponent(okayButton);
SetOkayButton(okayButton);
MakeActiveWindow();
}
};
gravityMode->SetActionCallback({ [this] {
c->SetGravityMode(gravityMode->GetOption().second);
if (gravityMode->GetOption().second == 3)
new GravityWindow(ui::Point(-1, -1), 50, customGravityX, customGravityY, c);
} });
tempLabel = new ui::Label(ui::Point(8, currentY), ui::Point(Size.X-96, 16), "Gravity Simulation Mode");
tempLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
@ -432,6 +509,8 @@ void OptionsView::NotifySettingsChanged(OptionsModel * sender)
ambientAirTemp->SetText(sb.Build());
}
gravityMode->SetOption(sender->GetGravityMode());
customGravityX = sender->GetCustomGravityX();
customGravityY = sender->GetCustomGravityY();
decoSpace->SetOption(sender->GetDecoSpace());
edgeMode->SetOption(sender->GetEdgeMode());
scale->SetOption(sender->GetScale());

View File

@ -40,6 +40,7 @@ class OptionsView: public ui::Window
ui::Checkbox * includePressure;
ui::Checkbox * perfectCirclePressure;
ui::ScrollPanel * scrollPanel;
float customGravityX, customGravityY;
bool initializedAirTempPreview = false;
void UpdateAmbientAirTempPreview(float airTemp, bool isValid);
void UpdateAirTemp(String temp, bool isDefocus);

View File

@ -842,6 +842,7 @@ void LuaScriptInterface::initSimulationAPI()
{"gravityGrid", simulation_gravityGrid},
{"edgeMode", simulation_edgeMode},
{"gravityMode", simulation_gravityMode},
{"customGravity", simulation_customGravity},
{"airMode", simulation_airMode},
{"waterEqualisation", simulation_waterEqualisation},
{"waterEqualization", simulation_waterEqualisation},
@ -1964,6 +1965,26 @@ int LuaScriptInterface::simulation_gravityMode(lua_State * l)
return 0;
}
int LuaScriptInterface::simulation_customGravity(lua_State * l)
{
int acount = lua_gettop(l);
if (acount == 0)
{
lua_pushnumber(l, luacon_sim->customGravityX);
lua_pushnumber(l, luacon_sim->customGravityY);
return 2;
}
else if (acount == 1)
{
luacon_sim->customGravityX = 0.0f;
luacon_sim->customGravityY = luaL_optnumber(l, 1, 0.0f);
return 0;
}
luacon_sim->customGravityX = luaL_optnumber(l, 1, 0.0f);
luacon_sim->customGravityY = luaL_optnumber(l, 2, 0.0f);
return 0;
}
int LuaScriptInterface::simulation_airMode(lua_State * l)
{
int acount = lua_gettop(l);

View File

@ -101,6 +101,7 @@ class LuaScriptInterface: public CommandInterface
static int simulation_gravityGrid(lua_State * l);
static int simulation_edgeMode(lua_State * l);
static int simulation_gravityMode(lua_State * l);
static int simulation_customGravity(lua_State * l);
static int simulation_airMode(lua_State * l);
static int simulation_waterEqualisation(lua_State * l);
static int simulation_ambientAirTemp(lua_State * l);

View File

@ -115,13 +115,18 @@ void Air::update_airh(void)
dh += AIR_VADV*(1.0f-tx)*ty*((bmap_blockairh[j+1][i]&0x8) ? odh : hv[j+1][i]);
dh += AIR_VADV*tx*ty*((bmap_blockairh[j+1][i+1]&0x8) ? odh : hv[j+1][i+1]);
}
if(!sim.gravityMode)
{ //Vertical gravity only for the time being
float airdiff = hv[y-1][x]-hv[y][x];
if(airdiff>0 && !(bmap_blockairh[y-1][x]&0x8))
vy[y][x] -= airdiff/5000.0f;
}
ohv[y][x] = dh;
if (x>=2 && x<XRES/CELL-2 && y>=2 && y<YRES/CELL-2)
{
float convGravX, convGravY;
sim.GetGravityField(x*CELL, y*CELL, -1.0f, -1.0f, convGravX, convGravY);
auto weight = ((hv[y][x] - hv[y][x-1]) * convGravX + (hv[y][x] - hv[y-1][x]) * convGravY) / 5000.0f;
if (weight > 0 && !(bmap_blockairh[y-1][x]&0x8))
{
vx[y][x] += weight * convGravX;
vy[y][x] += weight * convGravY;
}
}
}
}
memcpy(hv, ohv, sizeof(hv));

View File

@ -545,6 +545,8 @@ void Simulation::SaveSimOptions(GameSave * gameSave)
if (!gameSave)
return;
gameSave->gravityMode = gravityMode;
gameSave->customGravityX = customGravityX;
gameSave->customGravityY = customGravityY;
gameSave->airMode = air->airMode;
gameSave->ambientAirTemp = air->ambientAirTemp;
gameSave->edgeMode = edgeMode;
@ -2834,8 +2836,19 @@ int Simulation::try_move(int i, int x, int y, int nx, int ny)
}
break;
case PT_CNCT:
if (y < ny && (TYP(pmap[y+1][x]) == PT_CNCT || TYP(pmap[y+1][x]) == PT_ROCK)) //check below CNCT for another CNCT or ROCK
return 0;
{
float cnctGravX, cnctGravY; // Calculate offset from gravity
GetGravityField(x, y, elements[PT_CNCT].Gravity, elements[PT_CNCT].Gravity, cnctGravX, cnctGravY);
int offsetX = 0, offsetY = 0;
if (cnctGravX > 0.0f) offsetX++;
else if (cnctGravX < 0.0f) offsetX--;
if (cnctGravY > 0.0f) offsetY++;
else if (cnctGravY < 0.0f) offsetY--;
if ((offsetX != 0) != (offsetY != 0) && // Is this a different position (avoid diagonals, doesn't work well)
((nx - x) * offsetX > 0 || (ny - y) * offsetY > 0) && // Is the destination particle below the moving particle
(TYP(pmap[y+offsetY][x+offsetX]) == PT_CNCT || TYP(pmap[y+offsetY][x+offsetX]) == PT_ROCK)) //check below CNCT for another CNCT or ROCK
return 0;
}
break;
case PT_GBMB:
if (parts[i].life > 0)
@ -3322,23 +3335,40 @@ int Simulation::create_part(int p, int x, int y, int t, int v)
void Simulation::GetGravityField(int x, int y, float particleGrav, float newtonGrav, float & pGravX, float & pGravY)
{
pGravX = newtonGrav*gravx[(y/CELL)*(XRES/CELL)+(x/CELL)];
pGravY = newtonGrav*gravy[(y/CELL)*(XRES/CELL)+(x/CELL)];
switch (gravityMode)
{
default:
case 0: //normal, vertical gravity
pGravY += particleGrav;
break;
case 1: //no gravity
break;
case 2: //radial gravity
if (x-XCNTR != 0 || y-YCNTR != 0)
default:
case 0: //normal, vertical gravity
pGravX = 0;
pGravY = particleGrav;
break;
case 1: //no gravity
pGravX = 0;
pGravY = 0;
break;
case 2: //radial gravity
{
pGravX = 0;
pGravY = 0;
auto dx = x-XCNTR;
auto dy = y-YCNTR;
if (dx || dy)
{
float pGravMult = particleGrav/sqrtf(float((x-XCNTR)*(x-XCNTR) + (y-YCNTR)*(y-YCNTR)));
pGravX -= pGravMult * (float)(x - XCNTR);
pGravY -= pGravMult * (float)(y - YCNTR);
auto pGravD = 0.01f - hypotf(dx, dy);
pGravX = particleGrav * (dx / pGravD);
pGravY = particleGrav * (dy / pGravD);
}
}
break;
case 3: //custom gravity
pGravX = particleGrav * customGravityX;
pGravY = particleGrav * customGravityY;
break;
}
if (newtonGrav)
{
pGravX += newtonGrav*gravx[(y/CELL)*(XRES/CELL)+(x/CELL)];
pGravY += newtonGrav*gravy[(y/CELL)*(XRES/CELL)+(x/CELL)];
}
}
@ -3467,7 +3497,6 @@ void Simulation::UpdateParticles(int start, int end)
int h_count = 0;
int surround[8];
int surround_hconduct[8];
float pGravX, pGravY, pGravD;
bool transitionOccurred;
//the main particle loop function, goes over all particles.
@ -3538,35 +3567,10 @@ void Simulation::UpdateParticles(int start, int end)
}
}
pGravX = pGravY = 0;
if (!(elements[t].Properties & TYPE_SOLID))
float pGravX = 0, pGravY = 0;
if (!(elements[t].Properties & TYPE_SOLID) && (elements[t].Gravity || elements[t].NewtonianGravity))
{
if (elements[t].Gravity)
{
//Gravity mode by Moach
switch (gravityMode)
{
default:
case 0:
pGravX = 0.0f;
pGravY = elements[t].Gravity;
break;
case 1:
pGravX = pGravY = 0.0f;
break;
case 2:
pGravD = 0.01f - hypotf(float(x - XCNTR), float(y - YCNTR));
pGravX = elements[t].Gravity * ((float)(x - XCNTR) / pGravD);
pGravY = elements[t].Gravity * ((float)(y - YCNTR) / pGravD);
break;
}
}
if (elements[t].NewtonianGravity)
{
//Get some gravity from the gravity map
pGravX += elements[t].NewtonianGravity * gravx[(y/CELL)*(XRES/CELL)+(x/CELL)];
pGravY += elements[t].NewtonianGravity * gravy[(y/CELL)*(XRES/CELL)+(x/CELL)];
}
GetGravityField(x, y, elements[t].Gravity, elements[t].NewtonianGravity, pGravX, pGravY);
}
//velocity updates for the particle
@ -3613,13 +3617,20 @@ void Simulation::UpdateParticles(int start, int end)
if (!legacy_enable)
{
if (y-2 >= 0 && y-2 < YRES && (elements[t].Properties&TYPE_LIQUID) && (t!=PT_GEL || gel_scale > (1 + RNG::Ref().between(0, 254)))) {//some heat convection for liquids
r = pmap[y-2][x];
if (!(!r || parts[i].type != TYP(r))) {
if (parts[i].temp>parts[ID(r)].temp) {
swappage = parts[i].temp;
parts[i].temp = parts[ID(r)].temp;
parts[ID(r)].temp = swappage;
if ((elements[t].Properties&TYPE_LIQUID) && (t!=PT_GEL || gel_scale > (1 + RNG::Ref().between(0, 254))))
{
float convGravX, convGravY;
GetGravityField(x, y, -2.0f, -2.0f, convGravX, convGravY);
int offsetX = std::round(convGravX + x);
int offsetY = std::round(convGravY + y);
if ((offsetX != x || offsetY != y) && offsetX >= 0 && offsetX < XRES && offsetY >= 0 && offsetY < YRES) {//some heat convection for liquids
r = pmap[offsetY][offsetX];
if (!(!r || parts[i].type != TYP(r))) {
if (parts[i].temp>parts[ID(r)].temp) {
swappage = parts[i].temp;
parts[i].temp = parts[ID(r)].temp;
parts[ID(r)].temp = swappage;
}
}
}
}
@ -4550,24 +4561,7 @@ killed:
for (j=0;j<rt;j++)
{
// Calculate overall gravity direction
switch (gravityMode)
{
default:
case 0:
pGravX = 0.0f;
pGravY = ptGrav;
break;
case 1:
pGravX = pGravY = 0.0f;
break;
case 2:
pGravD = 0.01f - hypotf(float(nx - XCNTR), float(ny - YCNTR));
pGravX = ptGrav * ((float)(nx - XCNTR) / pGravD);
pGravY = ptGrav * ((float)(ny - YCNTR) / pGravD);
break;
}
pGravX += gravx[(ny/CELL)*(XRES/CELL)+(nx/CELL)];
pGravY += gravy[(ny/CELL)*(XRES/CELL)+(nx/CELL)];
GetGravityField(nx, ny, ptGrav, 1.0f, pGravX, pGravY);
// Scale gravity vector so that the largest component is 1 pixel
if (fabsf(pGravY)>fabsf(pGravX))
mv = fabsf(pGravY);
@ -4622,24 +4616,7 @@ killed:
for (j=0;j<rt;j++)
{
// Calculate overall gravity direction
switch (gravityMode)
{
default:
case 0:
pGravX = 0.0f;
pGravY = ptGrav;
break;
case 1:
pGravX = pGravY = 0.0f;
break;
case 2:
pGravD = 0.01f - hypotf(float(nx - XCNTR), float(ny - YCNTR));
pGravX = ptGrav * ((float)(nx - XCNTR) / pGravD);
pGravY = ptGrav * ((float)(ny - YCNTR) / pGravD);
break;
}
pGravX += gravx[(ny/CELL)*(XRES/CELL)+(nx/CELL)];
pGravY += gravy[(ny/CELL)*(XRES/CELL)+(nx/CELL)];
GetGravityField(nx, ny, ptGrav, 1.0f, pGravX, pGravY);
// Scale gravity vector so that the largest component is 1 pixel
if (fabsf(pGravY)>fabsf(pGravX))
mv = fabsf(pGravY);
@ -5272,6 +5249,8 @@ Simulation::Simulation():
GSPEED(1),
edgeMode(0),
gravityMode(0),
customGravityX(0),
customGravityY(0),
legacy_enable(0),
aheat_enable(0),
water_equal_test(0),

View File

@ -105,6 +105,8 @@ public:
//Simulation Settings
int edgeMode;
int gravityMode;
float customGravityX;
float customGravityY;
int legacy_enable;
int aheat_enable;
int water_equal_test;

View File

@ -155,6 +155,10 @@ int Element_STKM_run_stickman(playerst *playerp, UPDATE_FUNC_ARGS)
gvy = ((float)(parts[i].y - YCNTR) / gravd);
}
break;
case 3:
gvx = sim->customGravityX;
gvy = sim->customGravityY;
break;
}
gvx += sim->gravx[((int)parts[i].y/CELL)*(XRES/CELL)+((int)parts[i].x/CELL)];