wow i dont understand how you got to the conclusion i want drag and drop, i despise drag and drop, aka visual programming, it disgusts me, i dont even like 3d scene builders. unity sucks, and i never saw game maker as an option.
im a programmer close to 10 years, i mostly did database based web aplications.
i started game programming with flashpunk an as3 flash framework, the competitor of flixel (most complex thing i did lately is to implement flow field algorithm for an rts game its actually a nice algorithem).
it(flashpunk) uses entity (a as3 class) and entity derived/extanded class as "actors"/game objects, an entity has most things you need for game objects : movment (with solid hit detection) hit collision detection (box and pixel based and even raycasting), rotation,alpha, basic maths (angel between point/entity, distance) sprite/image manipulation/animation (including tween), input handling,etc etc.
each entity has a type so you can get entities with "get by type" or collide by type.
thers also world, itsl like a screen, each world holds entites, while non active worlds entites are not active or visable, you change world to move between screens.
for example a pong game with this framework:
worlds: start screen, game screen, game over
entities:
paddle
ball
score
buttons
edit:the big thing is that its oop meaning a class encapsulates data and functions (methods) so all you need to do is : world.add(some_entity) , and dont worry about it the world will update it as it keeps a list of entites, and to remove its as easy world.remove(some_entity), no need to loop anything update a list/array,display object like sprite remove does it all.
btw agk has this when you add or remove a sprite(and images and sounds etc), why dont they make a way to do this with user defined types? that would make my life much easier with less boilerplate code.
i can do all this without that framework, as proof over the years i ported it(flashpunk framework) to at least 10+ engines and languages (i know it very intimately):
my first attempt after i was told flash is dead(decleard dead), there were no class in js yet so i used prototypes (the engine is dom based):
https://github.com/yoel123/yoel-html5-game-engine-tutorials
later i ported it to phaser js:
https://github.com/yoel123/yoel-phaser-js-framework
and then to java with slick 2d (java has oop):
https://github.com/yoel123/yoel-java-slick2d-framework
it lacked mobile so i ported it to corona sdk, lua has oop, but its a bit clumsy:
https://github.com/yoel123/corona-sdk-picking-sticks
i will also make a picking sticks for agk.
i also ported it to unity (i dont have the files).
ported to naalaa ( a basic dilect):
https://github.com/yoel123/naalaa-avoider-game
naalaa has types but no oop but i manged
blitz 3d port:
;//////////////////////main//////////////////////////
;create_y_world()
;Global y_camera,y_light,bla
;sphere = CreateSphere(32)
;EntityColor sphere ,250,0,0
;EntityAlpha sphere,0.5
;PositionEntity sphere,0,0,5
;EntityType sphere,sphere_col
;bla=y()
;test y_entity
;berrel = LoadMesh ("oildrum.3ds")
;PositionEntity berrel ,0.2,0,0
;ScaleEntity berrel ,0.05,0.05,0.05
;y_test. y_entity= create_y_entity(berrel ,0.1,2,5)
;y_test\pos\x=-0.1
;y_world_update()
;//////////////////////end main//////////////////////////
;////////////////////////world class///////////////////////////////
Global y_camera,y_light,campiv
;create world
Function create_y_world()
Graphics3D 640,480,16,2
SetBuffer BackBuffer ()
campiv= CreatePivot()
y_camera = CreateCamera(campiv)
;EntityAlpha campiv,1
y_light = CreateLight ()
End Function ;end create_y_world
;update world
Function y_world_update()
While Not KeyHit(1)
UpdateWorld
RenderWorld
;my updtae
y_my_update()
;update all entitis pos
For e.y_entity= Each y_entity
;update_y_entity(e)
;e\pos\x =e\pos\x -0.1
Next
Flip
Wend
End Function ;end y_world_update
;my update world
;Function y_my_update()
;End Function ;end y_my_update
;////////////////////////end world class///////////////////////////////
;/////////////////////////y_entity///////////////////////////////////
Type y_entity
Field grafic
Field pos.y_point
Field speed
Field solid
Field y_Type
End Type
;create y_entity
Function create_y_entity. y_entity(grafic, x, y, z, y_Type)
Local e. y_entity = New y_entity
e\pos.y_point = New y_point
e\pos\x = x
e\pos\y = y
e\pos\z = z
e\grafic = grafic
e\ y_Type = y_Type
PositionEntity e\grafic,e\pos\x,e\pos\y,e\pos\z
EntityType e\grafic , y_Type
Return e
End Function ;end create y_entity
;update y_entity
Function update_y_entity(e. y_entity)
;Local e. y_entity
PositionEntity e\grafic,e\pos\x,e\pos\y,e\pos\z
End Function ;end update y_entity
;/////////////////////////end y_entity///////////////////////////////////
;/////////////////////////y_point///////////////////////////////////
Type y_point
Field x#
Field y#
Field z#
End Type
;/////////////////////////end y_point///////////////////////////////////
;////////fps cam////
Function fps_cam()
TurnEntity campiv, 0, -MouseXSpeed ()/5.0, 0
TurnEntity y_camera, MouseYSpeed () /5.0, 0, 0 ;rotate camera up/down according to mouse Y movement
If EntityPitch(y_camera) < -45 ;don't allow camera to look below -45 degrees
RotateEntity y_camera, -45, EntityYaw(y_camera), EntityRoll(y_camera)
EndIf
If EntityPitch(y_camera) > 45 ;don't allow camera to look above 45 degrees
RotateEntity y_camera, 45, EntityYaw(y_camera), EntityRoll(y_camera)
EndIf
MoveMouse GraphicsWidth()/2, GraphicsHeight()/2 ;reset mouse position to middle of screen
End Function ;end fps cam
Function entity_control(e,speed#)
;e= y_camera
wkey = KeyDown(17) ;collect user input
skey = KeyDown(31) ;It's a good practice to collect these inputs only once
akey = KeyDown(30) ;per loop. This will prevent odd behaviors from happening,
dkey = KeyDown(32)
If KeyDown(203) Or akey Then MoveEntity e,-speed,0,0 ;left
If KeyDown(205) Or dkey Then MoveEntity e,speed,0,0;right
If KeyDown(208) Or skey Then MoveEntity e ,0,0,-speed;down
If KeyDown(200) Or wkey Then MoveEntity e,0,0, speed;up
End Function ;end entity control
Function y()
Print 123
sphere = CreateSphere(32)
;EntityColor sphere ,250,100,0
;EntityAlpha sphere,0.5
PositionEntity sphere,5,0,5
EntityType sphere,sphere_col
End Function
;End
and fnaly the agk port:
yengine.agk:
global count = 0
global current_world as yworld
global current_worldi //current world index
/*
its not ideal but to get current world you need:
worlds[current_worldi]
agk dosnt use refrences for vriables every var is its own place in the memory and dosnt point to another var
*/
global ysprite_count = 0
global yimg_count = 0
global ytxt_count = 0
global yimgs as yimg[]
global worlds as yworld[]
global ydebug as string
ydebug="debug:"
////////////////////////types/////////////////////////
TYPE yentity
id as integer
src as integer
rindex as integer
ytype as String
pos as ypoint
speed as float
yactive
alpha
rotation as float
frame
yints as integer[]
ystrings as String[]
yfloats as float[]
ENDTYPE
TYPE ypoint
x as float
y as float
z as float
ENDTYPE
TYPE yworld
name as String
yentitys as yentity[]
rindex
ENDTYPE
TYPE yimg
name as String
id
ENDTYPE
////////////////////////end types/////////////////////////
/////////////////engine funcs/////////////////////////////////////
function yengineupdate()
yworldupdate()
myupdate()
endfunction //yengineupdate
/////////////////end engine funcs/////////////////////////////////////
/////////////////////world funcs///////////////////////////////
//GetSpriteExists
//SetSpriteActive
//GetSpriteActive
function newyworld(name as string)
nw as yworld
nw.name = name
nw.rindex = worlds.length+1
worlds.insert(nw)
endfunction nw //newyworld
function changeworld(n as string)
//hide all worlds sprites
for i = 0 to worlds.length
for j = 0 to worlds[i].yentitys.length
SetSpriteVisible(worlds[i].yentitys[j].id,0)
//ydebug = ydebug+"--"+str(worlds[i].yentitys[j].id) + "--"
next j
next i
//change world
for i = 0 to worlds.length
//find name and set current world to this world
if worlds[i].name = n then current_worldi = i
next i
//show new world sprtes
for i = 0 to worlds[current_worldi].yentitys.length
SetSpriteVisible(worlds[current_worldi].yentitys[i].id,1)
//ydebug = ydebug +"xx"+ str(current_world.yentitys[i].id)+" xx"
next i
endfunction //changeworld
//add entity to current world
function yadd(e ref as yentity)
worlds[current_worldi].yentitys.insert(e)
endfunction //yadd
//add entity to a spesific world
function yaddw(w as string,e ref as yentity)
for i = 0 to worlds.length
//find name and add entity current world to this world
if worlds[i].name = w
e.rindex = worlds[i].yentitys.length+1 // save the yentitys array index
worlds[i].yentitys.insert(e)
endif
next i
endfunction //yaddw
function yremovew(w as string,e ref as yentity)
for i = 0 to worlds.length
//find name and add entity current world to this world
if worlds[i].name = w and worlds[i].yentitys.length <> -1 and GetSpriteExists(e.id)
// worlds[i].yentitys.remove(e.rindex)
worlds[i].yentitys[e.rindex].yactive = 0
DeleteSprite(e.id)
endif
next i
endfunction //end yremovew
function yworldupdate()
//shortcuts (to get data they are not refrences)
e as yentity
w as yworld
wi = current_worldi
w = worlds[wi]
print("wi"+str(wi))
//loop all entities in current world
for i = 0 to w.yentitys.length
e = worlds[wi].yentitys[i] //current entity
//if the entity sprite exists update entity
if GetSpriteExists(e.id)
update_yentity(worlds[wi].yentitys[i]) //e dosnt hold refrence
endif
next i
endfunction //yworldupdate
/////////////////////end world funcs///////////////////////////////
////////////////////////entity funcs///////////////////////////////////
function newyentity(x,y,speed,src_id)
//incrament sprite count
inc ysprite_count
//create new entity and populate its atts
ne as yentity
ne.pos.x = x
ne.pos.y = y
ne.speed = speed
ne.id = ysprite_count //give it some id
ne.src = src_id //image id
ne.ytype = "entity"
ne.yactive = 1
//create sprite
CreateSprite(ne.id,src_id)
//set start pos
SetSpritePosition(ne.id,ne.pos.x,ne.pos.y)
endfunction ne //newyentity
function update_yentity(e ref as yentity)
SetSpritePosition(e.id,e.pos.x,e.pos.y)
//add rotation and alpha
endfunction yimg_count//update_yentity
function move_by(e ref as yentity,sx as float,sy as float)
//no refrences so have to use current_world itself
i = current_worldi
worlds[i].yentitys[e.rindex].pos.x = worlds[i].yentitys[e.rindex].pos.x +sx
worlds[i].yentitys[e.rindex].pos.y = worlds[i].yentitys[e.rindex].pos.y +sy
//print(e.pos.x)
endfunction //tst
function get_by_type(t as string)
es as yentity[]
for i = 0 to worlds[current_worldi].yentitys.length
//if type and active
if t = worlds[current_worldi].yentitys[i].ytype and worlds[current_worldi].yentitys[i].yactive=1
es.insert(worlds[current_worldi].yentitys[i])
endif
next i
endfunction es
function hit_test(e ref as yentity,t as string)
ret as yentity
es as yentity[]
es = get_by_type(t)
for i = 0 to es.length
if GetSpriteCollision( e.id, es[i].id ) =1 then ret = es[i]
next i
endfunction ret
function is_clicked(e ref as yentity)
ret = 0
if ( GetPointerPressed ( ) = 1 )
sid = GetSpriteHit ( GetPointerX ( ), GetPointerY ( ) )
if sid = e.id then ret = 1
endif
endfunction ret //end is_clicked
function ise(e ref as yentity)
ret = GetSpriteExists(e.id)
endfunction ret
//change entity intager val
function ei_change(e as yentity,pos,yval)
i = current_worldi
worlds[i].yentitys[e.rindex].yints[pos] = worlds[i].yentitys[e.rindex].yints[pos]+yval
endfunction
function sx(e ref as yentity,x)
i = current_worldi
worlds[i].yentitys[e.rindex].pos.x = x
endfunction
function sy(e ref as yentity,y)
i = current_worldi
worlds[i].yentitys[e.rindex].pos.y = y
endfunction
////////////////////////end entity funcs///////////////////////////////////
/////////////////////////util funcs//////////////////////////
function yaddimg(src)
inc yimg_count
//load img
//(yimg_count,src)
endfunction yimg_count//tst
/////////////////////////end util funcs//////////////////////////
function tst()
Print("tst")
endfunction //tst
main.agk (you will need ph.png placeholder in media flder):
// Project: yengine
// Created: 2021-05-07
// show all errors
SetErrorMode(2)
// set window properties
SetWindowTitle( "yengine" )
SetWindowSize( 1024, 768, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window
// set display properties
SetVirtualResolution( 1024, 768 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 30, 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
#insert "yengine2d.agc"
LoadImage(1,"ph.png")
tstw as yworld
tstwt as yworld
tstw = newyworld("game")
tstwt = newyworld("menu")
//current_world = tstw
tste as yentity
bullet as yentity
target as yentity
global tste2 as yentity
tste = newyentity(50,50,1,1)
tste2 = newyentity(250,50,1,1)
tste.ytype = "tst"
tste2.ytype = "btn"
bullet = newyentity(50,250,2,1)
target = newyentity(350,250,1,1)
bullet.ytype = "bullet"
target.ytype = "target"
target.yints=[1,0]//hp (one way to do this)
target.yints.insert(1)//hp (another way todo this)
//yadd(tste)
yaddw("game",tste)
yaddw("game",bullet)
yaddw("game",target)
yaddw("menu",tste2)
changeworld("menu")
do
print(ydebug)
//move_by(tste,tste.speed,0)
//move_by(current_world.yentitys[0],tste.speed,0)
//update_yentity(tste)
//yworldupdate()
yengineupdate()
Sync()
loop
global tsttimer = 0
function myupdate()
if worlds[current_worldi].name="game"
print("in game")
//make tst type move
tstts as yentity[]
tstts = get_by_type("tst") // get al ts types
for i = 0 to tstts.length //loop them
move_by(tstts[i],tstts[i].speed,0) //test move by
if tsttimer>100 then yremovew("game",tstts[i]) //test remove with fake timer
next i
if tstts.length >=0 then print( "is tst exist: "+str(ise(tstts[0])) )
inc tsttimer//incrament fake timer
bullets_update()
endif
if worlds[current_worldi].name="menu"
update_menu_world()
endif
endfunction
function update_menu_world()
print("in menu")
//click tste2 to change to game world
if is_clicked(tste2) then changeworld("game")
endfunction
function bullets_update()
bs as yentity[]
//loop all bullets
bs = get_by_type("bullet") // get al ts types
for i = 0 to bs.length //loop them
move_by(bs[i],bs[i].speed,0) //test move by
//sx(bs[i],bs[i].pos.x-1) //test sx sy
bullets_hit(bs[i])
next i
endfunction
function bullets_hit(b ref as yentity)
t as yentity
ts as yentity[]
t = hit_test(b,"target")
if ise(t) //ise = GetSpriteExists for yentity
print("target hit")
ei_change(t,0,-1)
endif
ts = get_by_type("target")
print("target hp: "+str(ts[0].yints[0]))
endfunction
im still pissed thers no proper refrence variables like:
a = "bla"
b = a
b = b + " holubalu!"
print(a)//prints bla
print(b) //prints bla holubalu!
dosnt seem anoying? lets see
im_a_very_long_object_array[i].pos.x = 5
//im a short var to refrence the line before for readabilety and fun
ex = im_a_very_long_object_array[i].pos.x //short for entity x
speed = 1
ex = ex +speed
print(ex)//prints 6
print(im_a_very_long_object_array[i].pos.x) //prints 5.....why me why
so i have to use im_a_very_long_object_array[i].pos.x to update that entities pos (or create a function for that) .
agk seems like a very powerful toll with many platform support and everything you need to make a game out ob the box the basics and luxury features.
i would prefer to use its basic scripting language (if i wanted cpp i would have used a diffrent free engine).
somtimes simple is better for faster devlopment.
but no oop is very hard for somone who is very used to and fond of oop.
again it dosnt even have proper references.
if somone has an advise or a workaround (or a feature i dont know about) it will help me a lot.