Author Topic: Shoot the Moon  (Read 715 times)

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Shoot the Moon
« on: December 15, 2014, 03:46:13 pm »


               

<squeaking...>


 


So, yeah. I'm busy lately. But I made these cool Celestial Orbs for someone...


moondialsun.png


 


Only someone else would really appreciate it if I wrote the scripts intended to work with them :-P


 


I may, one day, but not anytime soon ;-(


 


So, does anyone want to contribute to this project?


 


Write a script that will:


  • Activate the Sun at Dawn and deactivate it at Dusk.

  • Activate the Moon at moonrise and deactivate it at moonset.

  • Advance the moon (change facing) around the moondial based on the day of the month.

Credit will of course be given and I'm sure at least three people will be very grateful =)


 


<...with rust>



               
               

               
            

Legacy_Tarot Redhand

  • Hero Member
  • *****
  • Posts: 4165
  • Karma: +0/-0
Shoot the Moon
« Reply #1 on: December 15, 2014, 05:29:12 pm »


               

What is the length of the lunar month? Earth's is approx 29 days or from wikipedia


 


A synodic month is the most familiar lunar cycle, defined as the time interval between two consecutive occurrences of a particular phase (such as new moon or full moon) as seen by an observer on Earth. The mean length of the synodic month is 29.53059 days (29 days, 12 hours,44 minutes, 2.8 seconds).

 


TR



               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Shoot the Moon
« Reply #2 on: December 15, 2014, 06:42:39 pm »


               


What is the length of the lunar month? Earth's is approx 29 days or from wikipedia


 


 


TR




I think that would want to be settable by the builder ...


               
               

               
            

Legacy_Tarot Redhand

  • Hero Member
  • *****
  • Posts: 4165
  • Karma: +0/-0
Shoot the Moon
« Reply #3 on: December 15, 2014, 08:18:17 pm »


               

The reason for asking that is because to do the last you need three pieces of information - two 2d vectors and an angle.


 


  • vector 1 - current x,y of the moon

  • vector 2 - location (x,y) of the centre of the circle that the moon orbits around

  • angle - the angle that the moon needs rotate (haven't checked but probably in radians). To get this angle calculate (number describing one whole travel around the centre)/(number of days in month

 


TR



               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Shoot the Moon
« Reply #4 on: December 15, 2014, 09:19:18 pm »


               

<complicating...>


 


Actually, the origin of the moon is the center of the circle, so all you need to do is calculate the new facing based on % of lunar cycle * 360 degrees 


SetFacing(fDirection); With fDirection being in degrees. An offset might be provided for moondials not aligned to true north, also.


 


If *I* were doing the script, Lunar period (I think is the right term for how fast it goes around the planet, and determining Moonrise and Moonset) and Lunar cycle (how long it takes for one complete cycle of phases) would be local vars, letting builders customize things.


 


<...simpler things>



               
               

               
            

Legacy_Tarot Redhand

  • Hero Member
  • *****
  • Posts: 4165
  • Karma: +0/-0
Shoot the Moon
« Reply #5 on: December 16, 2014, 02:37:58 am »


               
<sounds of sobbing & hair being torn out>

 

From your illustration there are a number of symbols on the floor, each representing a particular phase of the moon. These symbols are arranged in a circle. You referred to it as a moondial somewhat akin to what some old mechanical clocks had. Therefore the moon is required to travel around the circumference of said circle. In order to do that I need the moon to be a totally separate object with its own centre and not an identical centre to the damned dial!!!!! I have just spent an hour and a half trying to figure out why the pretty standard small routine I use for such a thing didn't work. Doing it in code has many advantages over the locked version.

 

Here is the code



#include "x0_i0_position"
 
location orbit(float fAngle, location lcurrent, location lcentre)
{
    float fFacing = GetFacingFromLocation(lcurrent);
    object oArea = GetAreaFromLocation(lcurrent);
    vector vStartPosition = GetPositionFromLocation(lcurrent);
    vector vCentrePos = GetPositionFromLocation(lcentre);
    vector vNewPosition;
 
//theoretically move moon to centre
 
    float fOldX = vStartPosition.x - vCentrePos.x;
    float fOldY = vStartPosition.y - vCentrePos.y;
 
//rotate about the origin (0,0)
 
    float fSine = sin(fAngle);
    float fCosine = cos(fAngle);
    float fWorkingX = fOldX * fCosine - fOldY * fSine;
    float fWorkingY = fOldX * fSine + fOldY * fCosine;
 
//theoretically move moon to new position
 
    vNewPosition = Vector(fWorkingX + vCentrePos.x, fWorkingY + vCentrePos.y, vStartPosition.z);
 
    return (Location(oArea, vNewPosition, fFacing));
}
 
void main()
{
    object oMoon = GetObjectByTag("CelestialOrbMoon");
    object oDial = GetObjectByTag("CelestialOrbMoondial");
    location lMoon = GetLocation(oMoon);
    location lDial = GetLocation(oDial);
    location lNewLocation = orbit(5.0f, lMoon, lDial);
    MoveToNewLocation(lNewLocation, oMoon);
}


That would have worked (might have needed tweaking but...)


 


<wanders off shaking head and muttering imprecations under breath>


 


TR



               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Shoot the Moon
« Reply #6 on: December 16, 2014, 02:47:56 am »


               

<looks totally confused...>


 


Um, the dial *is* a separate model. All three parts are separate, but all have an origin at the same center point. So you place/spawn all three at the same location. Then you setfacing on the moon... either continuously or every 45 degrees... You don't *move* the moon... The sphere is hanging off to the side of the origin by 5m...


 


I'm soooo confused!


 


<...and feels like it, too>



               
               

               
            

Legacy_Grymmly

  • Newbie
  • *
  • Posts: 6
  • Karma: +0/-0
Shoot the Moon
« Reply #7 on: December 16, 2014, 02:59:29 am »


               

Okay, I haven't read all of the posts fully, but here is what I know:  Because of the offset of the moon object from it's actual center, just rotating the object is all that is needed to move the moon around the dial.


I'm not a scripter by any means, but I think all that is needed is to detect what day it is (start with a day 0 and go from there up to 28 days, which is the approximate cycle of the moon) and for every X days (X being the number of moon symbols on the dial divided into 28) rotate the object the appropriate number of degrees (I think rolo said 45 degrees?).


               
               

               
            

Legacy_Tarot Redhand

  • Hero Member
  • *****
  • Posts: 4165
  • Karma: +0/-0
Shoot the Moon
« Reply #8 on: December 16, 2014, 03:37:49 am »


               

In computer graphics the origin is set to either 0,0 for 2d or 0,0,0 for 3d. When you perform a vector rotation it is in relation to that origin. In NwN the origin is set to be the south west corner, with no elevation, of an area. By making the moon, the sun and the dial all have the same location (as in adjust location) I can only rotate the moon about it's own axis.


 


TR



               
               

               
            

Legacy_Tarot Redhand

  • Hero Member
  • *****
  • Posts: 4165
  • Karma: +0/-0
Shoot the Moon
« Reply #9 on: December 16, 2014, 04:19:53 pm »


               

I have just posted what I hope is an even clearer explanation in the existing thread on using vectors.


 


TR



               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Shoot the Moon
« Reply #10 on: December 19, 2014, 02:38:56 am »


               <spinning...>


Good explanation, TR, but... Not wanting to waste valuable time, I designed the moon orb so that the only thing a script needs to do is rotate it. The moon's spherical mesh is located 5 meters away from its pivot point (which was what I meant by origin).


Load up the demo mod and hit rotate in the toolset and you'll see what I meant.


I wanted to keep the scripting as simple as possible, doing the geometry in the model, rather than the game ;-/


<...in place>
               
               

               
            

Legacy_Tarot Redhand

  • Hero Member
  • *****
  • Posts: 4165
  • Karma: +0/-0
Shoot the Moon
« Reply #11 on: December 20, 2014, 08:10:27 am »


               
The saga of "The Moving Moon" or "How I Learned to Love Pulling my Hair Out" (apologies to the late Stanley Kubrick)

 

So Rolo wants his moon to travel around that dial. He keeps mentioning rotation. Now I know that rotation won't work but... So I write the code to do rotation just to prove it. As expected the moon duly rotates about the SW corner of the area. Here is the demo code. It goes in the OnHeartbeat of the area.



#include "x0_i0_position"
 
location Rotate(float fAngle, location lcurrent, object oArea);
void MovePlaceable(location lNewLocation, object oPlaceable, string sResRef);
 
void main()
{
    object oMoon = GetObjectByTag("CelestialOrbMoon");
    location lMoon = GetLocation(oMoon);
    object oArea = GetAreaFromLocation(lMoon);
    location lNewLocation = Rotate(12.0f, lMoon, oArea);
    vector vToHere = GetPositionFromLocation(lNewLocation);
 
// only move to a location if it is inside the area
 
    if((vToHere.x >= 0.0f) && (vToHere.y >= 0.0f))
    {
        if(vToHere.x < IntToFloat(GetAreaSize(AREA_WIDTH, oArea) * 10 - 1))
        {
            if(vToHere.y < IntToFloat(GetAreaSize(AREA_HEIGHT, oArea) * 10 - 1))
                MovePlaceable(lNewLocation, oMoon, "blueprint001");
        }
    }
}
 
location Rotate(float fAngle, location lcurrent, object oArea)
{
    float fFacing = GetFacingFromLocation(lcurrent);
    vector vStartPosition = GetPositionFromLocation(lcurrent);
 
//rotate about the origin (0,0)
 
    float fSine = sin(fAngle);
    float fCosine = cos(fAngle);
    float fNewX = vStartPosition.x * fCosine - vStartPosition.y * fSine;
    float fNewY = vStartPosition.x * fSine + vStartPosition.y * fCosine;
    float fNewZ = vStartPosition.z;
 
    vector vNewPosition = Vector(fNewX,fNewY,fNewZ);
 
    return (Location(oArea, vNewPosition, fFacing));
}
 
void MovePlaceable(location lNewLocation, object oPlaceable, string sResRef)
{
    int iStatic = GetUseableFlag(oPlaceable);
    object oNew = CreateObject(OBJECT_TYPE_PLACEABLE, sResRef, lNewLocation, FALSE);
    if(iStatic)
        SetUseableFlag(oPlaceable, 1);
    DestroyObject(oPlaceable, 0.5);
}


I did however have an idea of what might work. If you look at the area in the toolset with the moon selected, you will see the directional arrow which tells you the facing of the placeable. If you don't spot it straight away, that's OK. Unlike most placeables, with this moon it is not in the immediate vicinity of it but in the (rough) centre of the dial and pointing at the (x,y) centre of the moon. So I thought that if I could change the facing I could make the moon orbit the centre of the dial. And it works (but see later). Again, here is the demo code. It goes in the OnHeartbeat of the area.



void main()
{
    object oMoon = GetObjectByTag("CelestialOrbMoon");
    location lMoon = GetLocation(oMoon);
    object oArea = GetAreaFromLocation(lMoon);
 
    int iStatic = GetUseableFlag(oMoon);
    if(GetLocalInt(oArea, "iIsFirstTime"))
    {
        SetLocalInt(oArea, "iIsFirstTime", FALSE);
        SetLocalFloat(oArea, "fFaceDirection", GetFacing(oMoon));
        return;
    }
 
    float fNewDirection = GetLocalFloat(oArea, "fFaceDirection");
    fNewDirection = fNewDirection - 12.0f;
 
    if(fNewDirection < 0.0f)
        fNewDirection = 360.0f - fNewDirection;
 
    SetLocalFloat(oArea, "fFaceDirection", fNewDirection);
 
    if(iStatic)
        SetUseableFlag(oMoon, 1);
 
    DestroyObject(oMoon, 0.01f);
 
    object oNew = CreateObject(OBJECT_TYPE_PLACEABLE, "blueprint001", lMoon, FALSE);
    AssignCommand(oNew, SetFacing(fNewDirection));
 
}


The above code could do with optimizing of course. The main problem is that you can only change the facing of an object once it exists and the OnSpawn event doesn't exist for placeables. So what happens is that the new moon is created in exactly the same position as the old moon. Even putting the call to DestroyObject before the call to CreateObject doesn't help as objects do not disappear immediately but rather fade away. Now this wouldn't matter too much except when hb code is called there is a doubling of light because of 2 moons being there instead of one.

 

Hair restorer anyone, please...

 

TR


               
               

               
            

Legacy_Proleric

  • Hero Member
  • *****
  • Posts: 1750
  • Karma: +0/-0
Shoot the Moon
« Reply #12 on: December 20, 2014, 09:43:27 am »


               

To create a new placeable with a different facing,


 


vector vMoon = GetPositionFromLocation(lMoon);
object oNew = CreateObject(OBJECT_TYPE_PLACEABLE, "blueprint001", Location(oArea, vMoon, fNewDirection), FALSE);

 


You've probably seen the Orrery and Moons of Krynn, which use animation instead.



               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Shoot the Moon
« Reply #13 on: December 20, 2014, 05:48:11 pm »


               

<feels like he is...>


 


Ok, let me try a demo...


 


I wrote a simple script just to demonstrate the rotation of the moon. I used GetTimeSecond() because Minute only counts to 1 (counts realtime minutes 2 per game hour, whereas hour counts game hours... Be nice to get game minutes...) and GetTimeHour is too slow for the demo (and too fast for the orb :-P Which should be based on day of the month (& hour?)).


 



   Spoiler
   


 


And in game...


HuT0DS5.png


 


What I was hoping for was a low impact way to trigger the setfacing once a game-hour, and to check the time for moonrise/set and sunrise/set...


 


<...speaking in tongues>



               
               

               
            

Legacy_Tarot Redhand

  • Hero Member
  • *****
  • Posts: 4165
  • Karma: +0/-0
Shoot the Moon
« Reply #14 on: December 20, 2014, 10:51:00 pm »


               

Well I didn't think mine was too bad considering that the facing routine was written in just a few minutes during a bout of insomnia at  5am this morning.


 


TR