This is one tool of a series, I am working on.
Why? I tried the free FirstPersonShooterCreatorClassic model packs or short FPSC Classic models. And wanted to make them work without hassle in AGK.
The *.X-files are not working everytime in AppGameKit, and mostly need FPE (FPSC Classic / GameGuru prefab files) with aditional data. But often these files are also only very simple with information.
This tool is for creating your own "animations" with new names and later play them. Often you can't play an animation from FPSC Classic by name, so with this tool, we could come a little bit closer.
Tweening and so on is not implemented. Also this code is not free of the possibility to break it. At this moment there are no keyboard shortcuts, but it makes re-framing or create your own "FPE"-files more easy.
Why? --> later I am planing on creating the Kenny-OBJ putter, where you could put also your FPSC Classic figures and with animation-names we are a step closer to have an animation software like "Plotagon", "Alice 3D"

help:
First button in the list, to "open" the animation into the GUI in the top.
After changing your values, press "Update", so the changed values are in the LIST.
To save the LIST, press "SAVE" (blue button)
for ROTATION find the rotation-button in the top-left. Press till the position is right for you.
Auto-load of the LIST, but no auto-save. Rotation will not be saved.
// Project: FLSetBuilder
// Author : xaby
// Reason : creating key-frames for own animations, re-framing, maybe for scripted cut-scenes
// dates : YYYY-MM-DD
// begin : 2018-12-19
// stand : 2018-12-12
// Created: 2018-12-12
// show all errors
SetErrorMode(2)
// set window properties
SetWindowTitle( "FLSetBuilder" )
SetWindowSize( 1280, 720, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window
// set display properties
SetVirtualResolution( 1280, 720 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 6000, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default fonts
global fps_scale# as float
global fps_target# as float
fps_target# = 100 // this is for calculation feeling. (1000 would be how many steps in 1 ms you want to go.) for better handling, it is about 100 FPS, so the numbers are easier to write
global gplayer_obj as integer
global gplayer_img as integer
LoadDefaultPlayer()
SetCameraPosition(1,0,70,-180)
SetCameraLookAt(1,0,60,0,0)
// ----> Animation helper -----> from ... to .... name -> in array-List
// Save -> Tweens, Animation of Objects / Cameras
//SetVirtualButtonText(
/*
Print( "Animation: "+GetObjectAnimationName(gplayer_obj,1))
Print( "Max-Frames: "+Str(GetObjectAnimationDuration(gplayer_obj,GetObjectAnimationName(gplayer_obj,1)),2))
*/
Type own_anim
name$ as String
frames as integer
beginframe as integer // maybe as float, but the numbers are still
endframe as integer
speed as float
tid as integer // text-id, for changing texts, not needed in saving later :-(, not the best ModelViewControl-shema
objid as integer // oject_id for the instance of the mini-animation object
EndType
global anim as own_anim[1]
anim[1].name$ = GetObjectAnimationName(gplayer_obj,1)
anim[1].frames = GetObjectAnimationDuration(gplayer_obj,GetObjectAnimationName(gplayer_obj,1))
//SetTextFontImage(
Function CreateGadgetList()
EndFunction
Function AddSpinGadget()
EndFunction
Function MakeAnimButtons()
// buttons needed: (<<) Start (>>) [Name-Editor] (<<) End (>>) [Speed+][Speed-] [Update] [Add]
i = 1
btn = 7
AddVirtualButton(i*btn+0, 850,30+i*40,32) // how to change the size of the text?
SetVirtualButtonText(i*btn+0,"<<") // how to change the size of the text?
AddVirtualButton(i*btn+1, 890,30+i*40,32) // how to change the size of the text?
SetVirtualButtonText(i*btn+1,">>") // how to change the size of the text?
AddVirtualButton(i*btn+2,1090,30+i*40,32)
SetVirtualButtonText(i*btn+2,"<<")
AddVirtualButton(i*btn+3,1130,30+i*40,32)
SetVirtualButtonText(i*btn+3,">>")
AddVirtualButton(i*btn+4,1170,30+i*40,38)
SetVirtualButtonText(i*btn+4,"update")
AddVirtualButton(i*btn+5,1230,30+i*40,38)
SetVirtualButtonText(i*btn+5,"SAVE")
CreateText(i*3+0,Str(anim[i].beginframe))
SetTextColor(i*3+0,250,250,250,255)
SetTextPosition(i*3+0,940-30,40*i+0)
SetTextSize( i*3+0,16)
CreateText(i*3+1,Str(anim[i].endframe))
SetTextColor(i*3+1,250,250,250,255)
SetTextPosition(i*3+1,940+30,40*i+0)
SetTextSize( i*3+1,16)
// 940,
CreateEditBox(i+0)
SetEditBoxPosition(i+0, 910,20+i*40)
SetEditBoxText(i+0, anim[i].name$)
CreateEditBox(i+1)
SetEditBoxPosition(i+1, 830,20)
SetEditBoxText(i+1, str(anim[i].beginframe))
CreateEditBox(i+2)
SetEditBoxPosition(i+2, 1000,20)
SetEditBoxText(i+2, Str(anim[i].endframe))
EndFunction
Function ReadAnim(name$ as string)
sep$ = chr(9)
if GetFileExists(name$)
f=OpenToRead(name$)
If f>0
for k=1 to anim.length-1 // implement FPE-PreFab-Reader here! or better JSON-thingly?
S$ = ReadLine(f)
anim[k].name$ = GetStringToken2(S$,sep$,1)
anim[k].beginframe = Val(GetStringToken2(S$,sep$,2))
anim[k].endframe = Val(GetStringToken2(S$,sep$,3))
anim[k].frames = anim[k].endframe - anim[k].beginframe
anim[k].speed = 1
// for update visuals
index = k
Text$ = "Anim: "+anim[index].name$+" : "+Str(anim[index].beginframe)+" : "+Str(anim[index].endframe)
if GetObjectExists(anim[index].objid)=1
PlayObjectAnimation(anim[index].objid,"",anim[index].beginframe,anim[index].endframe,1,0.01)
endif
if GetTextExists(anim[index].tid) = 1
SetTextString(anim[index].tid,Text$) // has to be created first, so AddAnim() first!
endif
next
CloseFile(f)
EndIf
EndIf
EndFunction
Function SaveAnim(name$ as string)
sep$ = chr(9)
f=OpenToWrite(name$)
If f>0
for k=1 to anim.length // implement FPE-PreFab-Reader here! or better JSON-thingly?
S$ = anim[k].name$ + Sep$ + Str(anim[k].beginframe) + Sep$ + Str(anim[k].endframe)
WriteLine(f,S$)
next
CloseFile(f)
EndIf
EndFunction
Function AddAnim(index as integer)
i = 1
btn = 7
element as own_anim
if index < 0
anim.insert(element)
index = anim.length-1
else
endif
anim[index].name$ = GetEditBoxText(i)
anim[index].beginframe = Val(GetTextString(i*3+0))
anim[index].endframe = Val(GetTextString(i*3+1))
anim[index].frames = anim[index].endframe - anim[index].beginframe
anim[index].speed = 1
Text$ = "Anim: "+anim[index].name$+" : "+Str(anim[index].beginframe)+" : "+Str(anim[index].endframe)
if GetTextExists(anim[index].tid) = 0
anim[index].tid = CreateText(Text$)
SetTextPosition(anim[index].tid,920,100+(index+1)*15-35)
SetTextSize(anim[index].tid,16)
endif
SetTextString(anim[index].tid,Text$)
if GetVirtualButtonExists(2*btn + 1 + index)
else
AddVirtualButton(2*btn + 1 + index ,900,(index)*15+90,15)
//SetVirtualButtonColor(2*btn + 1 + index , 200,200,200)
endif
EndFunction
Function SetAnimValues(index as integer)
i = 1
SetEditBoxText(i, anim[index].name$ )
SetTextString(i*3+0, Str(anim[index].beginframe))
SetTextString(i*3+1, Str(anim[index].endframe))
//anim[index].frames = anim[index].endframe - anim[index].beginframe // not implemented in GUI
//anim[index].speed = 1
EndFunction
anim[1].beginframe = 0
anim[1].endframe = anim[1].frames
MakeAnimButtons()
SetPrintSize(40)
SetObjectAnimationSpeed(gplayer_obj,24)
for o=1 to 35
AddAnim(-1)
anim[anim.length-1].objid = InstanceObject(gplayer_obj)
/* --> Scaling is buggy,
X# = 0.25
Y# = 0.25
Z# = 0.25
SetObjectScale(anim[anim.length-1].objid,X#,Y#,Z#)
*/
// So my instances are far far away instead
SetObjectPosition(anim[anim.length-1].objid,-450+(mod ((o-1),6))*35,180-((o-1)/6)*75,600)
PlayObjectAnimation(anim[anim.length-1].objid,"",anim[anim.length-1].beginframe,anim[anim.length-1].endframe,1,0.01)
next
SetVirtualButtonColor(12,100,200,255) // save-button
AddVirtualButton(13,340,30,40)
SetVirtualButtonText(13,"Rotate")
SetVirtualButtonColor(13,250,100,250)
animfile$ = "anim.ani.txt"
ReadAnim(animfile$)
gmax = 0
/*
For i=1 to 10
AddVirtualButton(i*3+0, 880,30+i*40,32) // how to change the size of the text?
SetVirtualButtonText(i*3+0,"<<") // how to change the size of the text?
AddVirtualButton(i*3+1,1090,30+i*40,32)
SetVirtualButtonText(i*3+1,">>")
AddVirtualButton(i*3+2,1140,30+i*40,38)
SetVirtualButtonText(i*3+2,"ADD")
CreateEditBox(i)
SetEditBoxPosition(i, 910,20+i*40)
//SetEditBoxTextSize( i, 36 )
Next
*/
btx = 16
do
Print( "FPS: "+Str(ScreenFPS(),2) )
Print( "Current-Frame: "+Str(GetObjectAnimationTime(gplayer_obj),2) )
//DrawText( 3 )
/*Print( Str(gmax))
if GetObjectAnimationTime(gplayer_obj) > gmax
SetObjectAnimationSpeed(gplayer_obj,998) // to get max-frame-count
gmax = GetObjectAnimationTime(gplayer_obj)
else
SetObjectAnimationSpeed(gplayer_obj,24)
endif
*/
Sync()
// RotateObjectGlobalY(gplayer_obj,MoveObjFPS(1))
DrawGUI()
If GetVirtualButtonReleased(11) // update
AddAnim(btx-15)
SetVirtualButtonColor(11,200,100,200)
PlayObjectAnimation(anim[btx-15].objid,"",anim[btx-15].beginframe,anim[btx-15].endframe,1,0.01)
PlayObjectAnimation(gplayer_obj,"",anim[btx-15].beginframe,anim[btx-15].endframe,1,0.01)
EndIf
For bt = 1 to 100
if GetVirtualButtonExists(bt)
if bt>15
if GetVirtualButtonReleased(bt)
btx = bt
SetAnimValues(btx-15)
PlayObjectAnimation(gplayer_obj,"",anim[btx-15].beginframe,anim[btx-15].endframe,1,0.01)
// current frame ... maybe from the tiny-preview animations?
Endif
endif
endif
Next
For bt = 1 to 100
if GetVirtualButtonExists(bt)
if bt>15
if bt <> btx
SetVirtualButtonColor(bt, 120,120,120)
SetTextColor(anim[bt-15].tid,120,120,120,255)
SetObjectColor(anim[bt-15].objid,100,100,100,255)
else
SetVirtualButtonColor(bt, 150,255,150)
SetTextColor(anim[bt-15].tid,150,255,150,255)
SetObjectColor(anim[bt-15].objid,255,255,255,255)
Endif
endif
endif
Next
//If GetVirtualButtonPressed(1) // I ask for "1", but error message is "0"
// --> if if first value smaller then second! app will break, so proper testing has to be implemented
If GetVirtualButtonPressed(7) // can't press 1000 times :-(
// but using ButtonState is not FrameRate-independent
SetTextString(3,Str(Val(GetTextString(3))-1))
EndIf
If GetVirtualButtonPressed(8)
SetTextString(3,Str(Val(GetTextString(3))+1))
EndIf
If GetVirtualButtonPressed(9)
SetTextString(4,Str(Val(GetTextString(4))-1))
EndIf
If GetVirtualButtonPressed(10)
SetTextString(4,Str(Val(GetTextString(4))+1))
EndIf
If GetEditBoxChanged(2)
SetTextString(3, Str(Val(GetEditBoxText(2))))
EndIf
If GetEditBoxChanged(3)
SetTextString(4, Str(Val(GetEditBoxText(3))))
EndIf
//--------------- Checking if first smaller then second, no one should be greater then max-frames, not testing for that yet
If Val(GetTextString(3))<0
SetTextString(3,Str(0))
EndIf
If Val(GetTextString(4))<=Val(GetTextString(3))
SetTextString(4, Str(Val(GetTextString(3))+1)) // same Frame breaks the game, so one frame has to be at least
EndIf
//---------------
If GetVirtualButtonPressed(12) // Save?
SaveAnim(animfile$)
EndIf
If GetVirtualButtonState(13) = 1
RotateObjectGlobalY( gplayer_obj,60.0 / ScreenFPS() * 2)
//SetVirtualButtonColor(13,100,100,100)
EndIf
loop
//FixObjectToObject
Function DrawGUI()
DrawLine(10,650,1260,650,255,255,255)
DrawLine(10,700,1260,700,255,255,255)
EndFunction
Function LoadDefaultPlayer()
gplayer_obj = LoadObjectWithChildren("xabys/Charzomb.x")
gplayer_img = LoadImage("xabys/default_colored.png")
SetObjectImage(gplayer_obj,gplayer_img,0)
SetObjectPosition(gplayer_obj,0,-GetObjectSizeMinY(gplayer_obj),0)
//SetObjectAnimationFrame()
//SetObjectAnimationSpeed()
PlayObjectAnimation(gplayer_obj,"",0,10000,1,0.01)
EndFunction
Function MoveObjFPS(units# as float)
newunits# as float
newunits# = fps_target# / ScreenFPS() * units#
EndFunction newunits#
Hope, you enjoy. It is not perfect. There are fixed 35 animations at this moment. And it works with the Zombie from FPSC Classic. Feel free, to change the skin. Photoshop file is also here.
Please tell me, what you think about, what you maybe wish or what I could have done more easily. The code is a proof of concept. It is a mess. No strict Model-View-Control at this moment.
Animation Sequences are not implemented yet. Like tweening stacks or chains. And also not implemented: Loop / No-Loop, Speed positive, play backwards ...
sitting_on_ground 32 39
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
idle_standing 209 233
walking 235 259
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
Anim-1 0 2497
0 0
Sometimes reading to much, so I have to look into that. But does not break yet