|
www.icons8.com |
This script shows how to automate the setup and start of a program, so only a click is needed to run everything how it's needed.
This is the "Tutorial08" included in the Tutorial-Download.
This is a complex tutorial, because it contains three things at once:
1) The replacement of a sprite with a real 3D model
2) Use the SID as a random number generator to control the 3D model
3) Use changes in C64 memory to control the 3D model
To 1)
This is an easy part; like replacing character, sprites can also replaced by 3D
models. To replace the sprite set the modelIndex in the
OnSprite() function to a value non zero.
The OnGetSprite() function will then be called, where the
filename of the 3D model is provided for the given modelIndex.
To 2)
The SID is configured in the OnLoad() function to produce a
noise waveform on oscillator three. In the OnFrameEnd()
function the current wave-sample is read and used to set the rotation speed of
our second ghost.
To 3)
This the fun part: In the OnLoad() function a condition (SetCondition())
is created, that will trigger the OnCondition() function of the
script, if the condition is fullfilled.
Note: Observing a memory address or a register e.g. in the OnFrameEnd() function
would maybe also work (like in 2)), but it might not hit a specific value change
("polling").
A condition is much faster and more reliable.
The used condition CPU.MWA (see
Breakpoints) will trigger, when the 6502 CPU writes anything into the
address 32768. So we can now read the value and do some logic with it.
In our case two conditions are create, to oberserve memory writing to address
32768 and 32769, which control the rotation (spriteRotationY1) and
apperance (blueGhost) of the first sprite.
const int startProgramTimerId = 1;
float spriteRotationY1 = 180.0;
float spriteRotationY1Dir = -1.0;
float spriteRotationY2 = 180.0;
float spriteRotationY2Dir = -1.0;
float spriteRotationX = 0.0;
float spriteRotationXDir = -1.0;
float ghostScale = 0.020;
bool blueGhost = false;
// This is called, when we loaded the script-file
void OnLoad(bool reloaded)
{
string scriptPath = APP.GetScriptPath();
APP.ClearDepthMaps(); // Clear all loaded depth maps
APP.ClearModels(); // Clear all loaded model
// Set the view mode to the new 3D
APP.ViewMode = ViewMode::Ext3D;
// Set the ambient light color and brigtness
APP.SetAmbientLight(0.3, 0.3, 0.3);
// Set the direction of the light (from the middle off the
scene (x), from top to bottom (y) and back to forth (z))
APP.SetLightDir(0.0, -1.0, +1.0);
// Position the scene, so we have the top/left in the middle
of the screen
E3D.SetScenePosition(0.44, -0.20, +0.01);
// Rotate the scene a little bit, so we can see the 3D effect
E3D.SetSceneOrientation(-25.0, -28.0, 0.0, 0.0); // yaw,
pitch, roll in degree, speed
// Setup the SID to produce random values on
oscillator 3 without making noise (see OnFrameEnd())
SID.Freq[2] = 5000;
SID.Attack[2] = 0;
SID.Decay[2] = 0;
SID.Sustain[2] = 15;
SID.Release[2] = 0;
SID.Control[2] =
SIDCtrl::NOISE | SIDCtrl::GATE;
SID.OSC3Off = true;
SID.Volume = 15;
// Create a condition 1, that will notify us, when CPU writes into memory at
32768 (see OnCondition())
C64.SetCondition(1, { "CPU.MWA=32768" }, "DataInputRot");
// Create a condition 2, that will notify us, when CPU writes into memory at
32769 (see OnCondition())
C64.SetCondition(2, { "CPU.MWA=32769" }, "DataInputType");
if (!reloaded)
{
// Load our "game"
APP.Load(scriptPath + "Sprites.prg", 0);
SetTimer(startProgramTimerId, 120, false);
}
}
bool OnSprite(int mode, SpriteInfo& spriteInfo,
BlockManipulation&
spriteManipulation)
{
spriteManipulation.ambient = 0.35;
spriteManipulation.xScale = ghostScale;
spriteManipulation.yScale = ghostScale;
spriteManipulation.zScale = ghostScale;
spriteManipulation.rotationAxis1 = Rotation::Y; // some animated rotation (see
OnFrameEnd())
spriteManipulation.rotationAxis2 = Rotation::X;
spriteManipulation.rotation2 = spriteRotationX;
if (spriteInfo.index == 0)
{ // Ghost 1
spriteManipulation.modelIndex = blueGhost ? 3 : 1;
spriteManipulation.rotation1 = spriteRotationY1;
}
else if (spriteInfo.index == 1)
{ // Ghost 2
spriteManipulation.modelIndex = 2;
// When modelIndex is not zero, then a 3D model file is request in the
OnGetModel() function
spriteManipulation.rotation1 = spriteRotationY2;
}
spriteManipulation.zTranslation -= 0.03; // translate the sprites a little mit
more in foreground
return true;
}
void OnCondition(int device, int
conditionId, string data)
{
// Check which condition fired and then read the data written to memory
if (conditionId == 1)
{
int pokedValue = C64.Read(32768);
//GUI.ShowInfoMessage("Poked value $32768 = " + formatInt(pokedValue));
spriteRotationY1 = 90.0 + pokedValue; // rotate the sprite to the "poked" angle
}
else if (conditionId == 2)
{
int pokedValue = C64.Read(32769);
//GUI.ShowInfoMessage("Poked valuee $32769 = " + formatInt(pokedValue));
blueGhost = (pokedValue != 0); // enable the blue ghost, if "poked" value is not
zero
}
}
float extraSpeed = 0.0;
void OnFrameEnd()
{
int oscChannel3 = SID.OSC3; // Read the oscillator 3 wave sample (noise should
produce a "random" value)
if (oscChannel3 < 4)
{
float s = oscChannel3;
extraSpeed = (s / 2.0); // Some simple logic to let the ghost rotate more
randomly (extraSpeed)
}
// Just some simple rotation around x and y axis
if (spriteRotationY2 > 225.0 && spriteRotationY2Dir > 0.0)
spriteRotationY2Dir = -0.7 - extraSpeed;
else if (spriteRotationY2 < 110.0 && spriteRotationY2Dir < 0.0)
spriteRotationY2Dir = +0.7 + extraSpeed;
spriteRotationY2 += spriteRotationY2Dir;
if (spriteRotationX < -10.0 && spriteRotationXDir < 0.0)
spriteRotationXDir = 0.15;
else if (spriteRotationX > 20.0 && spriteRotationXDir > 0.0)
spriteRotationXDir = -0.15;
spriteRotationX += spriteRotationXDir;
}
bool OnGetModel(int mode, int index,
ModelDescription& modelDescription)
{
modelDescription.renderSides =
RenderSides::RenderSidesFront;
string scriptPath = APP.GetScriptPath();
switch (index)
{
case 1: modelDescription.objFile = scriptPath + "3D\\Ghosts\\Ghost3-8-3.obj";
return(true);
case 2: modelDescription.objFile = scriptPath + "3D\\Ghosts\\Ghost3-8-4.obj";
return(true);
case 3: modelDescription.objFile = scriptPath + "3D\\Ghosts\\Ghost3-7-2.obj";
return(true); // Panic Ghosts
default: break;
}
return(false);
}
void OnTimer(int timerId)
{
if (timerId == startProgramTimerId)
{
APP.SendASCII("RUN\n");
}
}