Quick Links: Download Gideros Studio | Gideros Documentation | Gideros Development Center | Gideros community chat | DONATE
80's style demos in Gideros — Gideros Forum

80's style demos in Gideros

hgy29hgy29 Maintainer
edited April 2023 in Relax cafe
Hi folks,

You certainly have noticed that the new trends in software development are based on IA and 'No code'. They want to make us believe that code is 'has been': ChatGPT can code for you, you can use graphical editors instead of code, etc.
I love Gideros because it is code centered, and because I grew up and learned to code by typing code listings from magazines in the 80's (They were standard MSX, STMag, Hebdogiciel).

In that time, there were contests to write small demo programs. The best demos would then be published and rewarded ('best' here could mean various things: beautiful, technically interesting, etc). Typical restrictions would apply: using a specific language, number of characters or lines below a limit, etc.

What would you think about defining something similar for Gideros ? Constraints would be:
- Using lua/gideros (obviously)
- No more than 100 lines, no more than 3k characters (in the event we'd like to publish them in a magzine)
- One single file of code (a main.lua)
- No additional assets (builtin Gideros font is allowed)
- No plugins (pure Gideros only).
- No UrlLoader
- Use of Gideros supplied lua libraries allowed

Any thought ?

Likes: SinisterSoft

+1 -1 (+1 / -0 )Share on Facebook
«13

Comments

  • piepie Member
    I would add
    - no plugins allowed, pure gideros lua only.

    I only fear that we are a too small community to have a contest like that, even if we are one of the best community that ever existed, gideros is awesome and reliable and Lua is gold.
    However I'd like to see where we could go from here.. I wonder if we could somehow engage with other lua communities like from Love or Solaris, and catch 'em all! :p
  • hgy29hgy29 Maintainer
    yes, no plugin allowed nor fetches using UrlLoader. I share the same fear, but I also see it as a way to promote Gideros with short demo codes that could be shared on social networks or, who knows, paper media.

    If we can make stunning demos with short codes, that's a way to say: "see, coding isn't hard with Gideros".

    Likes: pie

    +1 -1 (+1 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    edited April 2023
    A few ideas that could be fit for those 'shorties': a brick breaker game, an end less runner, a pong game, a tic tac toe.

    I have a 3D Maze generator (which I wrote in lua for Roblox) that would certainly fit too
  • piepie Member
    edited April 2023
    Maybe we could invite some historical community members lost on the way to come back for the contest, they would probably make wonders (I still see some of them in the TOP POSTERS list :) )

    Likes: hgy29

    +1 -1 (+1 / -0 )Share on Facebook
  • although I like the idea of small code template, I fear those contests :/ (where to post games, picking a winner, getting people to join, ...). Game Jams are very hard to promote and get people involved imho.

    I would be more interested in a gideros fanzine :) Like a monthly release with all the good stuff, but who will make it? how long of personal time would we have to invest? ...

    Gideros has a wonderful wiki (imho), this could (should) be the place to promote how awesome gideros is.
    my growING GIDEROS github repositories: https://github.com/mokalux?tab=repositories
  • hgy29hgy29 Maintainer
    We're definetly not enough on the forum to speak about 'contest', and there wouldn't be any reward, except being featured in a fanzine (even if it is a single article fanzine to start with). The idea is in the end is to produce a paper quarterly with code examples and publish them on FB/Twitter/Insta etc in an effort to attract new users.

    Ideally that paper would also contain short tutorials about coding with gideros, from very basic lua to advanced stuff, in the hope that it could get picked up by school/teachers or novices.
  • piepie Member
    edited April 2023
    @hgy29 Since you put this insane idea out I tried building one: this is called SPAMFIGHTER
    93 lines of code and 2737 characters, some of which are comments.
    I think it might be optimized better and insert a "play again" and a score somewhere, but I am already satisfied with the result :smiley:
    GET YOURS OUT! :D

    Play it here: http://giderosmobile.com/code/bfKYQRvPhsQY7uOmJfEJS2JE8n1vfnxD
    --Piretro Software SPAMFIGHTER 2023 Pietro Eccher - pure gideros lua mini game
    Swidth = application:getDeviceWidth()
    Sheight = application:getDeviceHeight()
    --getRandomColor
    local function getRdnCol()
    	local color_digits = {0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'}
    	local out =""
    	for i =1, 6 do 
    		out = out..color_digits[math.random(#color_digits)]
    	end
    	return out
    end
    --popup class
    Popup = Core.class(Sprite)
    function Popup:init()
    	local txts = {"BUY!!", "SAVE MORE!", "ENLARGE YOUR BRAIN", "SAY YES!", "NO TO NO!", "YES TO NO!", "MAKE BIG BUCKS!", "PRINCE OF NIGERIA HERE"}
    	local txtgfx =  TextField.new(nil, "\e[color=#"..getRdnCol().."]"..txts[math.random(#txts)].."\e[color]")
    	txtgfx:setScale(2) 
    	local x,y,w,h = txtgfx:getBounds(self)
    	local image =  Pixel.new("0x"..getRdnCol(), 1, w+50, h+50)
    	self:addChild(image)
    	image:addChild(txtgfx)
    	txtgfx:setPosition(25, 40)	
    	--close popup
    	local xb = Pixel.new(0x0, 1, 20, 20)
    	self:addChild(xb)
    	xb:setPosition(w+35, -10)
    	local xbt = TextField.new(nil, "\e[color=#fff]X\e[color]")
    	xbt:setScale(2) 
    	xbt:setPosition(6,17)
    	xb:addChild(xbt)
    	--drag popup
    	local function onMD(self, event)
    		if xb:hitTestPoint(event.x, event.y) then			
    			self:removeFromParent()
    			self = nil
    			p=p-1 
    			spamMaster(math.random(0,7))
    		elseif image:hitTestPoint(event.x, event.y) then
    			self.isFocus = true 
    			self.x0 = event.x
    			self.y0 = event.y
    			event:stopPropagation() 
    			stage:addChild(self)
    		end
    	end
     
    	local function onMM(self, event)
    		if self.isFocus then
    			local dx, dy = event.x - self.x0, event.y - self.y0
    			self:setX(self:getX() + dx) 
    			self:setY(self:getY() + dy)
    			self.x0, self.y0 = event.x, event.y
    			event:stopPropagation()
    		end
    	end
     
    	local function onMU(self, event)
    		if self.isFocus then
    			self.isFocus = false 
    			spamMaster(math.random(25))
    			event:stopPropagation()
    		end
    	end	 
    	image:addEventListener(Event.MOUSE_DOWN, onMD, self)
    	image:addEventListener(Event.MOUSE_MOVE, onMM, self)
    	image:addEventListener(Event.MOUSE_UP, onMU, self)	
    end
     
    local function clickspam()	
    	print("clickspam")
    	spamMaster(math.random(25))
    end
    p = "0"
    --drop popup
    function spamMaster(n) 
    	if p == 0 then 
    		p = TextField.new(nil, "\e[color=#000]YOU WIN\e[color]") 
    		p:setScale(4) p:setPosition(100,100) stage:addChild(p) else
    		for i = 1, n do
    			local popup = Popup.new()
    			stage:addChild(popup)
    			local w, h = popup:getWidth()*.5, popup:getHeight()*.5
    			local maxw, maxh = math.floor(Swidth-w), math.floor(Sheight-h)
    			local rx,ry  = math.random(-w, maxw ), math.random(-h, maxh)
    			popup:setPosition(rx, ry)
    			p=p+1
    		end
    	end
    end
    spamMaster(math.random(3))

    Likes: hgy29

    +1 -1 (+1 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    edited April 2023
    Fantastic @pie, it proves the whole idea isn't bad.

    Here is mine:
    - 91 lines
    - 3054 characters (I can reduce further, it depends if we define 3k=3000 or 3072)
    - Needs gideros lua libraries (3dbase and luashader)
    Laby=Core.class(Sprite,function(sz) end)
    function Laby:init(sz)
    	self.sz=sz
    	local szw=sz*2+1 self.szWalls=szw
    	local cube=D3.Cube.new(.5,.5,.5) self:addChild(cube)
    	cube:updateMode(D3.Mesh.MODE_LIGHTING,0)
    	cube:setInstanceCount(szw^2)
    	self.cube=cube
    	self:clear()
    	self:setScale(1/szw,1/szw,1/szw)
    end
    function Laby:clear()
    	self.data={} local szw=self.szWalls
    	local matrix=Matrix.new() self.cube:setLocalMatrix(matrix)
    	for i=1,szw^2 do
    		local x=(i-1)%szw
    		local y=((i-1)//szw)%szw
    		matrix:setPosition(x-(szw-1)/2,0,y-(szw-1)/2)
    		self.cube:setInstanceMatrix(i,matrix)
    	end
    	self.cube:updateInstances()
    end
    function Laby:make()
    	local entry=math.random(self.sz)
    	self:clearDot(1,entry,-1,0,true)
    	local exit=math.random(self.sz)
    	self:clearDot(self.sz,exit,1,0,true)
    	self.entry=entry
    	self.exit=exit
    	self:search(1,entry)
    end
    function Laby:search(px,py)
    	self:clearDot(px,py,0,0)
    	local dirs={ vector(1,0), vector(-1,0), vector(0,1), vector(0,-1)}
    	local td=math.random(4)
    	local found
    	for i=1,4 do
    		local ndir=dirs[(i+td)%4+1]
    		local nx,ny=px+ndir.x,py+ndir.y
    		if self:checkDot(nx,ny) then
    			self:clearDot(nx,ny,-ndir.x,-ndir.y)
    			if nx==self.sz and ny==self.exit then
    				self:clearDot(nx,ny,0,0,true)
    				self:clearDot(nx,ny,-ndir.x,-ndir.y,true)
    				found=true
    			else
    				local sf=self:search(nx,ny)
    				if sf then self:clearDot(nx,ny,-ndir.x,-ndir.y,true) end
    				found=found or sf
    			end
    		end
    	end
    	if found then self:clearDot(px,py,0,0,true) end
    	return found
    end
    function Laby:clearDot(x,y,dx,dy,m)
    	local px,py,szw=x*2-1+dx,y*2-1+dy,self.szWalls
    	local di=px+py*szw
    	self.data[di]=if m then 1 else 0
    	local matrix=Matrix.new()
    	matrix:setPosition(px-(szw-1)/2,-1000,py-(szw-1)/2)
    	self.cube:setInstanceMatrix(di+1,matrix)
    	self.cube:updateInstances()	Core.yield(true)
    end
    function Laby:checkDot(x,y)
    	if x<1 or y<1 or x>self.sz or y>self.sz then return false end
    	local px,py=x*2-1,y*2-1
    	return not self.data[px+py*self.szWalls]
    end
     
    --Create on scene
    Lighting.setLight(8,16,8,0.3) Lighting.setLightTarget(0,0,0,60,10)
    local sw,sh=application:getContentWidth(),application:getContentHeight()
    local sky=Pixel.new(0xFFFFFF,1,sw*3,sh*3) sky:setColor(0x00FFFF,1,0x0040FF,1,90) sky:setPosition(-sw,-sh) stage:addChild(sky)
    local view=D3.View.new(sw,sh,45,0.1,100) stage:addChild(view) local scn=view:getScene()
    local gplane=D3.Mesh.new() scn:addChild(gplane)
    gplane:setColorTransform(0,0.8,0.3,1)
    local n,z=100,-0.2 gplane:setVertexArray{-n,z,-n, n,z,-n, n,z,n, -n,z,n}
    gplane:setGenericArray(3,Shader.DFLOAT,3,4,{0,1,0,0,1,0,0,1,0,0,1,0,})
    gplane:setIndexArray{1,2,3,1,3,4}
    gplane:updateMode(D3.Mesh.MODE_LIGHTING|D3.Mesh.MODE_SHADOW,0)
    local l=Laby.new(20,20) scn:addChild(l)
     
    local a=0 
    stage:addEventListener(Event.ENTER_FRAME,function()
    	a=a+1 local ac,as=math.cos(^<a),math.sin(^<a)
    	view:lookAt(ac,as*.3+.5,as,0,0,0)
    	Lighting.computeShadows(scn)
    end)
    Core.asyncCall(function() while true do l:clear() l:make() Core.yield(10) end end)

    Likes: pie, MoKaLux

    +1 -1 (+2 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    Thinking of it I think we should allow standard plugins, it would be silly to avoid box2d or similar plugins
  • hgy29hgy29 Maintainer
    @MoKaLux, @SinisterSoft, @keszegh and @vitalitymobile and all others, I count on you too!
    +1 -1 (+1 / -0 )Share on Facebook
  • piepie Member
    Yours is in another league :o
    I wonder how many lines of code will require to do the same thing in 2d 80s style B)
    hgy29 said:

    Thinking of it I think we should allow standard plugins, it would be silly to avoid box2d or similar plugins

    I am not sure: I'd say yes if it is going to be a showcase for the complete gideros features, no if the goal is to demonstrate the simple but deep approach to coding that gideros lua has.
    To me using libraries and plugins defies the original purpose to stick to something that can exist in a single lua file. Both approaches have pros and cons, and I won't say they can't coexist. Let's hear from the others too
  • hgy29hgy29 Maintainer
    Yes, there can be different categories, we could also ask for a specific theme, etc. Nothing really fixed forever anyhow, but I’d like them to be printable in a fanzine (thus no external assets and relatively short), and usable offline. As long as somehow can grab a fresh Gideros copy, type the code and run it, I am fine.
  • piepie Member
    Ok then I've wasted enough time for today... :D
    Here is another pure gideros lua, single file mini game: 49 lines of code and 1558 chars. This one with RETRY button too!!
    --Piretro Software The Click For Speed 2023 Pietro Eccher - pure gideros lua mini game - based on The Click For Speed mobile game by Nicola Danese
    application:setBackgroundColor(0x000)
    function getRdnCol()
    	local color_digits = {0,1,2,3,4,5,6,7,8,9}
    	local out =""
    	for i =1, 6 do 
    		out = out..color_digits[math.random(#color_digits)]
    	end
    	return out
    end
     
    tx = "\e[color=#FFF]Click on the WHITE SQUARE ASAP!"
    nf = TextField.new(nil, tx.."\e[color]")
    nf:setScale(3)
    nf:setPosition(440, 40)
    stage:addChild(nf)
    px = {}
    function newGame()
    	f = false
    	i = 0
    	for r=1, 20 do 
    		for c=1,20 do
    			i= i+1
    			px[i]= Pixel.new("0x"..getRdnCol(), 1, 20,20)
    			px[i]:setPosition(20*r,20*c)
    			stage:addChild(px[i])
    		end
    	end
    	st_time, n_time, w_time, ck_time, s  = os.time(), math.random(7), "", "", math.random(#px)
    end
    st_time, n_time, s  = os.time(), math.random(7), 1
    newGame()
    stage:addEventListener(Event.MOUSE_DOWN, function(e)
    										if px[s]:hitTestPoint(e.x, e.y) then
    											ck_time = os.timer() - w_time
    											nf:setText(tx.."\nClicked in "..ck_time.." seconds\nRETRY\e[color]")
    											f = true
    										end
    										if f == true and nf:hitTestPoint(e.x, e.y) then
    											nf:setText(tx.."\e[color]")
    											newGame()
    										end
    									end)
    stage:addEventListener(Event.ENTER_FRAME, function()	
    										if px[s] and px[s]:getColor()~=0xFFFFFF and os.time() - st_time > n_time then
    											px[s]:setColor(0xFFFFFF)
    											w_time = os.timer()
    										end
    									end)

    Likes: hgy29, MobAmuse

    +1 -1 (+2 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    Actually it is fun to write those mini games, I'll post another one soon (no libs, no plugins this time)

    Likes: pie

    +1 -1 (+1 / -0 )Share on Facebook
  • i will try to shrink one i made recently from 9k to 3k.
    meanwhile it would be great to put them on gideros page running as html so anybody can try out. or even better put them in some wrapper (scemenanaged) so only one gideros game needs to be rune and you can decide which demo to lead.

    Likes: pie

    +1 -1 (+1 / -0 )Share on Facebook
  • piepie Member
    edited April 2023
    keszegh said:

    i will try to shrink one i made recently from 9k to 3k.
    meanwhile it would be great to put them on gideros page running as html so anybody can try out. or even better put them in some wrapper (scemenanaged) so only one gideros game needs to be rune and you can decide which demo to lead.

    We already have a resource to do it! I almost forgot and it is a real true value to get new people, we should promote it!

    BTW I think it needs an update because not everything is working as it should right now :smile:

    SPAMFIGHTER
    http://giderosmobile.com/code/UVS1sXjq1Lf74uJXBnkCa3gt8FBy3eap
    [edit: http://giderosmobile.com/code/bfKYQRvPhsQY7uOmJfEJS2JE8n1vfnxD this is the retro version, which means that is 100% compatible with the current fiddle version.]

    The click for speed
    http://giderosmobile.com/code/hB4OSnmOSdEW4cJ1SZZVivWJZhnsfywE

    Likes: keszegh

    +1 -1 (+1 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    Another one:
    - 2632 characters
    - 76 lines
    - Pure gideros without plugins or libs
    Game=Core.class(Sprite)
    function Game:init()
    	stage:addChild(self)
    	local c,h={32,25,0,25},12 for i=0,32,2 do h=((h+4^math.random()-2)<>0)><24 c[#c+1]=i c[#c+1]=h end
    	c[8]=c[6] c[32]=c[30] 
    	local s=Path2D.new() s:setPath("ML*Z",c) s:setScale(10) s:setFillColor(0x808080,1)
    	s:setY(240) s:setLineColor(0,0) 
    	local r=RenderTarget.new(320,480,true) r:draw(s) self.r=r self:addChild(Bitmap.new(r)) 
    	local s=Path2D.new() s:setPath("ML",{240,c[30]*10+240,260,c[30]*10+240}) s:setLineColor(0x00FF00,1) self:addChild(s)
    	local ship=([[
    .......AA.......
    ......ACCA......
    .....ACCCCA.....
    ....ACCCCCCA....
    ....ACAAAACA....
    ...AAACCCCAAA...
    ..ACACCCCCCACA..
    .AAAAAAAAAAAAAA.
    .ACCCCACCACCCCA.
    ACCCCCACCACCCCCA
    ACCCCAACCAACCCCA
    .ACCCAAAAAACCCA.
    ..AAAABBBBAAAA..
    ......BBBB......
    ......BBBB......
    .......BB.......]]):gsub("[^%.ABC]","")
    	local ss=ship:gsub("[%.B]","000\0"):gsub("A",string.char(0xFF):rep(4)):gsub("C",string.char(0xC0,0xC0,0xC0,0xFF))
    	self.ship=Bitmap.new(Texture.new(ss,16,16,true))
    	local ss=ship:gsub("[%.AC]","000\0"):gsub("B",string.char(0xFF,0xC0,0x20,0xFF))
    	self.fire=Bitmap.new(Texture.new(ss,16,16,true)) self.ship:addChild(self.fire)
    	self:addChild(self.ship) self.fire:setVisible(false)
    	self.ship:setPosition(10,240+c[6]*10) self.ship:setAnchorPosition(8,13) self.bp=true self.spx,self.spy=0,0
     
    	stage:addEventListener(Event.MOUSE_DOWN,self.onMD,self)
    	stage:addEventListener(Event.MOUSE_UP,self.onMU,self)
    	stage:addEventListener(Event.MOUSE_MOVE,self.onMM,self)
    	Core.asyncCall(self.onF,self)
    end 
    function Game:won()
    	stage:removeAllListeners()
    	self.ship=nil
    end
    function Game:lost() 
    	self.ship=nil
    	stage:removeAllListeners()
    	self:removeFromParent()
    	Game.new()
    end
    function Game:onMD(e) self.fire:setVisible(true) self.vx=(e.x-160)/160 end
    function Game:onMU(e) self.fire:setVisible(false) self.vx=nil end
    function Game:onMM(e) self.vx=self.fire:isVisible() and (e.x-160)/160 end
    function Game:onF() while self.ship do 
    	local a,px,py=self.ship:getRotation(),self.ship:getPosition()
    	local bp=self.r:getPixel(px//1,py//1+1)>0
    	if self.vx then
    		self.spx+=math.sin(^<a)*.03
    		self.spy-=math.cos(^<a)*.03
    		a+=self.vx 
    	elseif not bp then
    		self.spy+=.02
    	elseif not self.bp then
    		if px>260 and px<280 and math.abs(math.sin(^<a))<.3 then
    			self:won()
    		else
    			self:lost()
    		end
    		break
    	end
    	px,py=((px+self.spx)><310)<>10,((py+self.spy)><480)<>0
    	self.ship:setRotation(a) self.ship:setPosition(px,py)
    	self.bp=bp
    Core.yield(true) end end 
    application:setBackgroundColor(0)
    application:setScaleMode("letterbox")
     
    Game.new()

    Likes: pie, MobAmuse

    +1 -1 (+2 / -0 )Share on Facebook
  • piepie Member
    hgy29 said:

    Another one:
    - 2632 characters
    - 76 lines
    - Pure gideros without plugins or libs

    :D I won't ever be an astronaut, I am unable to control it and you are a genius! I can follow only 20 lines of your code. Please in the future add some lines to explain what are you doing there :#

    Likes: MoKaLux

    +1 -1 (+1 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    pie said:

    Please in the future add some lines to explain what are you doing there :#

    Yeah, that’s the drawback of being constrained in number of lines, I have to write working but cryptic code ;) There is dark magic in this one, since assets aren’t allowed.

    Likes: pie

    +1 -1 (+1 / -0 )Share on Facebook
  • piepie Member
    edited April 2023
    hgy29 said:


    Yeah, that’s the drawback of being constrained in number of lines, I have to write working but cryptic code ;) There is dark magic in this one, since assets aren’t allowed.

    I'd love to see it expanded: your black magic is so black that isn't even working in the fiddle o:)
    local c,h={32,25,0,25},12 for i=0,32,2 do h=((h+4^math.random()-2)<>0)><24 c[#c+1]=i c[#c+1]=h end
    I think this line is taken directly from Alan Turing's secret diary

    Likes: MoKaLux

    +1 -1 (+1 / -0 )Share on Facebook
  • keszeghkeszegh Member
    edited April 2023
    a 2-player pong clone. decreasing from 9k to 6k went smooth, for the rest i needed to make some tricks and also i made it less easy to read (shortening variable names) - that is really the only downside of these size limitations. but overall it is exactly the same game as it was at 9k except for removing controller support (originally i made it to be played on android tv's with 2 tv remotes).
    EDIT: i keep updating it, last time i changed that it is a bit more friendly with different output resolutions.

    97 lines, 2772 chars:
    --pong clone by Balazs Keszegh
    --config: max points and up/down keys for 1st/2nd player:
    mP=5 
    up1k=KeyCode.W
    d1k=KeyCode.S
    up2k=KeyCode.UP
    d2k=KeyCode.DOWN
     
    _H=application:getLogicalWidth()
    _W=application:getLogicalHeight()
     
    application:setBackgroundColor(0x222222)
    _R = 0xd0432c
    _G = 0x0d7d00
    _M = 0xdddddd
     
    function init()	
      g=Sprite.new()  
      nS=mP*2-1 nG=_H/(nS*3+1) 
      nW=_H/100 nH=_H/(nS*3+1)*2
      bW=_H/20 bV=_H/60 
      pW=_W/64 pH=_H/6.75 pV=_H/100
      a={}
      c=Sprite.new()
      g:addChild(c)
      for i=1,nS do 
        local x=Pixel.new(_M,1,nW,nH)
        x:setAnchorPosition(nW/2,0)
        x:setPosition(_W/2,(i-1)*(nG+nH)+nG)
        c:addChild(x)
        a[i]=x   
      end
      p1=Pixel.new(_R,1,pW,pH)
      p1:setAnchorPosition(pW/2,pH/2)	
      g:addChild(p1)  
      p2=Pixel.new(_G,1,pW,pH)
      p2:setAnchorPosition(pW/2,pH/2)
      g:addChild(p2)
      b=Pixel.new(_M,1,bW,bW)
      b:setAnchorPosition(bW/2,bW/2)  
      reset()
     
      g:addChild(b)
      stage:addEventListener(Event.KEY_DOWN, key,true)    
      stage:addEventListener(Event.KEY_UP, key,false)        
      stage:addEventListener(Event.ENTER_FRAME, onEnterFrame,nil)
      return g
    end
     
    function key(y,event)	
      if event.keyCode == up1k then up1=y end
      if event.keyCode == d1k then dn1=y end
      if event.keyCode == up2k then up2=y end
      if event.keyCode == d2k then dn2=y end
    end
     
    function onEnterFrame()
      if (up1 and (not dn1)) and (p1:getY()>0) then p1:setY(p1:getY()-pV) end
      if (dn1 and (not up1)) and (p1:getY()<_H) then p1:setY(p1:getY()+pV) end
      if (up2 and (not dn2)) and (p2:getY()>0) then p2:setY(p2:getY()-pV) end
      if (dn2 and (not up2)) and (p2:getY()<_H) then p2:setY(p2:getY()+pV) end
      b:setPosition(b:getX()+bVX,b:getY()+bVY)
      if p1:hitTestPoint(b:getX()-bW/2,b:getY()) and bVX<0 then     
        local diff=(b:getY()-p1:getY())/pH
        bAngle=math.pi/2*diff    
        bVX=math.cos(bAngle)*bV
        bVY=math.sin(bAngle)*bV    
      end
      if p2:hitTestPoint(b:getX()+bW/2,b:getY()) and bVX>0 then 
        local diff=(b:getY()-p2:getY())/pH
        bAngle=math.pi/2*diff    
        bVX=-math.cos(bAngle)*bV
        bVY=math.sin(bAngle)*bV    
      end  
      if b:getX()>_W-bW/2 then bVX=-bVX pt1=pt1+1 a[pt1]:setColor(_R) end
      if b:getX()<bW/2 then bVX=-bVX pt2=pt2+1 a[nS+1-pt2]:setColor(_G) end
      if b:getY()<bW/2 then bVY=-bVY end
      if b:getY()>_H-bW/2 then bVY=-bVY end
      if pt1==mP or pt==mP then reset() end
    end
     
    function reset()
      pt1=0 pt2=0
      up1=false dn1=false up2=false dn2=false
      for i=1,nS do 
        a[i]:setColor(_M)
      end
      p1:setPosition(3*pW,_H/2)
      p2:setPosition(_W-3*pW,_H/2)
      b:setPosition(_W/2,_H/2)
      bAngle=math.random()*math.pi/2-math.pi/4
      bVX=math.cos(bAngle)*bV
      bVX=(math.random(2)*2-3)*bVX
      bVY=math.sin(bAngle)*bV
    end
     
    stage:addChild(init())
    +1 -1 (+4 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    May I add another constraint ? 40 characters per line max, for pagination purposes
    +1 -1 (+1 / -0 )Share on Facebook
  • edited May 2023
    @hgy29 For some things really cool, I need to read image data for noise or height map of terrain so can you allow some images?
    Coming soon
  • keszeghkeszegh Member
    you could random generate it perhaps in a few lines of code?
    +1 -1 (+1 / -0 )Share on Facebook
  • hgy29hgy29 Maintainer
    Hi @vitalitymobile, the reason for those restrictions is that I'd like to publish the codes (with your permissions) in a quarterly paper about Gideros, in a way that would allow people to just type the code in a Gideros Studio and launch it without further downloads. The only prerequisite will be to have Gideros installed.
    You can embed images in your code though, I did it for my 'lander' demo. You can base64 encode a png or a jpg and put it in plain text in your code too. You can also generate textures by code, using math.random or https://wiki.gideros.rocks/index.php/Math.noise
    +1 -1 (+3 / -0 )Share on Facebook
  • edited May 2023
    Thank @pie when seeing your game I remember the Flood-It game
    So I make it with a lot of code learn from you and @hgy29 and some other games on GitHub

    This is my version, 100 lines but 6.5k characters, I can make it shorter but I think it will be clear for you if you want to read something



    - Rules: From the Top-Left Cell, click any color so that you will flood fill the board with the same color in 25 moves

    I really enjoy when making this mini-game. Gideros really has OOP central code, we can make a game with nice and clear code!


    local dx = application:getLogicalTranslateX() / application:getLogicalScaleX() local dy = application:getLogicalTranslateY() / application:getLogicalScaleY() local w = application:getContentWidth() local h = application:getContentHeight()
    SCREEN = {Left = -dx, Top = -dy,Right = w + dx, Bottom = h + dy,W = dx*2 + w,H = dy*2 + h,Center = {x = w / 2, y = h / 2}}
    local color_list = {0xf94144,0xf3722c,0xf9c74f,0x90be6d,0x43aa8b,0x577590}
    local ROW,COL = 14,14
    local CELL_SIZE = math.floor((SCREEN.H)/ ROW)
    application:setBackgroundColor(0xa9d6e5)
    nf = TextField.new(nil, "Move/ToTal") nf:setScale(2) nf:setPosition(SCREEN.W - 150,50) stage:addChild(nf)
    tf_info = TextField.new(nil, "0/25") tf_info:setScale(2) tf_info:setPosition(SCREEN.W - 150,70) stage:addChild(tf_info)
    tf_game_state = TextField.new(nil, "Press r to restart") tf_game_state:setScale(1.5) tf_game_state:setPosition(SCREEN.W - 150,100) stage:addChild(tf_game_state)
    Game=Core.class(Sprite)
    function Game:init()
    	stage:addChild(self)
    	self:setPosition(SCREEN.Left,SCREEN.Top)
    	self.board = {}
    	self.sprite_board = Sprite.new()	
    	for row =1,ROW do
    		self.board[row] = {}
    		for col=1,COL do
    			local node = Pixel.new(0x000000, 1, CELL_SIZE,CELL_SIZE)
    			self.board[row][col] = node
    			self.sprite_board:addChild(node)
    			node:setPosition((col - 1) * CELL_SIZE, (row - 1) * CELL_SIZE)
    		end
    	end
    	self:workOnEachNode(self.initNeighbors)
    	self:addChild(self.sprite_board)
    	stage:addEventListener(Event.MOUSE_DOWN,self.onMD,self)
    	stage:addEventListener(Event.KEY_DOWN, self.keyPress,self) 
    end
    function Game:keyPress(event)	
      if event.keyCode == KeyCode.R then self:restart() end
    end
    function Game:workOnEachNode(workFnc)
    	local result
    	for row = 1, ROW do
    		for col= 1, COL do
    			result = workFnc(self,self.board[row][col],row,col)
    		end
    	end
    	return result
    end
    function Game:initNeighbors(node,row, col)
    	node.neighbors = {}
    	if (row - 1 > 0) then node.neighbors[#node.neighbors+1] = self.board[row -1][col] end if (row + 1 <= ROW) then node.neighbors[#node.neighbors+1] = self.board[row + 1][col] end if (col - 1 > 0) then node.neighbors[#node.neighbors+1] = self.board[row][col - 1] end if (col + 1 <= COL) then node.neighbors[#node.neighbors+1] = self.board[row][col + 1] end
    end
    function Game:restart()
    	self:workOnEachNode(function(self,node,row, col )
    			local value_random = math.random(1,#color_list)
    			node.color = value_random
    			node:setColor(color_list[value_random])
    			node.is_flooded = false
     
    	end)
    	self.board[1][1].is_flooded = true;
        self:floodNeighbors(self.board[1][1],self.board[1][1].color);
        self.move_count = 0
        self.max_move_count = 25
        tf_info:setText(self.move_count .."/"..self.max_move_count)
        self.can_click = true
        tf_game_state:setText("Press r to restart")
    end
    function Game:floodNeighbors(node, color)
    	for i = 1,#node.neighbors do self:floodTile(node.neighbors[i],color) end
    end
    function Game:floodTile(node, color)
    	if node.is_flooded then return end
    	if (node.color == color) then node.is_flooded = true self:floodNeighbors(node, color) end
    end
    function Game:changeColor(node,color)
    	node.color = color
    	node:setColor(color_list[color])	
    end
    function Game:onMD(event)
    	if self.sprite_board:hitTestPoint(event.x, event.y) then self:ClickBlock(event.x, event.y) event:stopPropagation() end	
    end
    function Game:ClickBlock(eventx, eventy)
    	if self.can_click == false then return end
    	local col = math.floor(eventx/CELL_SIZE) + 1
    	local row = math.floor(eventy/CELL_SIZE) + 1
    	self.move_count = self.move_count + 1
    	tf_info:setText(self.move_count .."/"..self.max_move_count)
    	self:floorBoardNow(self.board[row][col].color)
    	local test = self:testAllFlooded()
    	if ( (not test) and self.move_count >= self.max_move_count) then tf_game_state:setText("YOU LOSE!") self.can_click = false Timer.delayedCall(2000,  function() self:restart() end)	end
    	if (test and self.move_count <= self.max_move_count) then tf_game_state:setText("YOU WIN!") self.can_click = false Timer.delayedCall(2000, function() self:restart() end)	end
    end
    function Game:floorBoardNow(flood_color)
    	self:workOnEachNode(function(self,node,row, col )
    		if(node.is_flooded) then self:changeColor(node,flood_color) self:floodNeighbors(node,flood_color) end
    	end)
    end
    function Game:testAllFlooded()
    	for row = 1, ROW do
    		for col= 1, COL do
    			if(self.board[row][col].is_flooded == false) then return false end
    		end
    	end
        return true;
    end
    local game = Game.new() game:restart()

    Likes: MoKaLux, pie, MobAmuse

    Coming soon
    +1 -1 (+3 / -0 )Share on Facebook
  • PaulHPaulH Member
    I spent the morning giving this a try. Here's an 80's style game in 98 lines, a bit like Asteroids, but with a black hole in the center of the screen. You avoid the incoming asteroids while dealing with the gravity pulling you in. Each time you advance a level (2000 points) the game gets harder by having the asteroids get more abundant, or bigger, or less linear in their trajectory, or by having gravity increase.

    I broke lots of coding standards to squeeze this down to 98 lines. Later I might see about squeezing some sound into it.



    Here's the code:

    j1,j2,w,h=application:getLogicalBounds() cx,cy=w/2,h/2 ppl=2000
    dfs={"More Asteroids", "Bigger Asteroids", "Higher Gravity", "More Varied Asteroid Trajectories"}
    Sprite.gp=Sprite.getPosition Sprite.sp=Sprite.setPosition Sprite.gr=Sprite.getRotation Sprite.sr=Sprite.setRotation
    floor,wht,sqrt,min,max,rand,deg,rad,sin,cos=math.floor,0xffffff,math.sqrt,math.min,math.max,math.random,math.deg,math.rad,math.sin,math.cos
    application:setBackgroundColor(0x000010)
    function angle_between_points(x1, y1, x2, y2)
    local dy,dx = y2 - y1,x2 - x1
    if dx == 0 then if dy < 0 then return 180 else return 0 end elseif dy == 0 then if dx < 0 then return 270 else return 90 end end
    result = math.deg(math.atan(dx / dy)) if dy < 0 then return 180 + result elseif (dx < 0) then return 360 + result end return result
    end
    --[[stars--]]for i = 1,500 do s=Shape.new() s:setLineStyle(2, wht) s:moveTo(0,0) s:lineTo(0,0) s:endPath() s:sp(rand(0,w),rand(0,h)) s:setScale(rand(1,2)) s:setAlpha(rand(10,50)/100) stage:addChild(s) end
    --[[ship--]]ship_points = {0,2,0.3,2.5,0.6, 2,0, 0.6,0,0,1,2,1,4,2,5,2,3,3,3,3,7,2,7,2,6,1,5,1,6,0,5,0,0}
    ship = Sprite.new() s=Shape.new() s:setLineStyle(2, 0xffff00) s:setFillStyle(Shape.SOLID, 0x4040ff) s:beginPath() s:moveTo(0, 0) ssc=12 ship.size=7*ssc ship.name="ship"
    for i = 1, #ship_points/2 do s:lineTo(ship_points[i*2-1]*ssc,(ship_points[i*2]-3.5)*ssc) end
    for i = 1, #ship_points/2 do s:lineTo(-ship_points[i*2-1]*ssc,(ship_points[i*2]-3.5)*ssc) end s:endPath() ship:addChild(s)
    --[[blackhole--]] bhsize=50 local nl = 1000 bh=Sprite.new()
    for i = 1, nl do local s=Shape.new() bh:addChild(s) local b=rand(100,200) s:setLineStyle(3, 0xffffff) s:beginPath() local l = rand(0,1000)/1000 s.life=l*l
    s.a = rand(0,3600)*0.1 s:moveTo(0,0) s:lineTo(0,0) s:endPath() s:sp(rand(1,bhsize),rand(1,bhsize)) end
    bh:addEventListener(Event.ENTER_FRAME, function() for i = 1, bh:getNumChildren() do local ch = bh:getChildAt(i)
    ch:sr(rand(0,360)) ch.life = ch.life * 0.97 if ch.life < 0.05 then ch.life = rand(90,100)/100 ch.a = rand(0,3600)*0.1 end
    ch:sp(ch.life * sin(rad(ch.a)) * bhsize, ch.life * cos(rad(ch.a)) * bhsize) ch:setAlpha(1-ch.life) local br=(ch.life - 0.2)*2
    ch:setColorTransform(br,br,br) end end) stage:addChild(bh) bh:sp(cx, cy)
    exhaust_layer = Sprite.new() stage:addChild(exhaust_layer) asteroid_layer = Sprite.new() stage:addChild(asteroid_layer)
    --[[score display --]]score = 0 score_tf = TextField.new(nil, "SCORE:") score_tf:setScale(3) score_tf:sp(50, 50) score_tf:setTextColor(0xffff00) stage:addChild(score_tf)
    function cc(o) local x,y=o:gp() local sx,sy=ship:gp() local d=sqrt((x-sx)*(x-sx)+(y-sy)*(y-sy)) if not go and d < (o.size/2 + ship.size/2) then bs() end_game() end end
    function msg(t,p) if msgtf then msgtf:removeFromParent() end if t then msgtf = TextField.new(null,t) msgtf:setTextColor(0xffff00) stage:addChild(msgtf) msgtf:setScale(4)
    msgtf:sp((w-msgtf:getWidth()) / 2, 70) if not p then Timer.delayedCall(3000, msg) end end end
    function tip(t,p) if tiptf then tiptf:removeFromParent() end if t then tiptf = TextField.new(null,t) tiptf:setTextColor(0xffff00) stage:addChild(tiptf) tiptf:setScale(4)
    if go then return end
    local x = (w-tiptf:getWidth()) / 2 if p=="l" then x = 50 elseif p=="r" then x=w-50-tiptf:getWidth() end
    tiptf:sp(x, h-100) if not p then Timer.delayedCall(3000, tip) end end end
    function make_asteroid()
    local a, s = rand(0,3600) * 0.1, Shape.new() s.size = asteroid_size * 0.4 * rand(50,100)
    s.vx,s.vy=rand(-100,100) * asteroid_trajectory_factor * 0.1, rand(-100,100) * asteroid_trajectory_factor * 0.1
    s.vr=rand(-10,10)*0.1 s:setLineStyle(2, 0xffffff) s:setFillStyle(Shape.SOLID, 0xbbbbbb) s:beginPath() s:moveTo(0, s.size/2)
    for a=10,360,10 do s:lineTo(sin(rad(a))*s.size/2+rand(-10,10)*s.size/200,cos(rad(a))*s.size/2 + rand(-10,10)*s.size/200) end s:lineTo(0,s.size/2) s:endPath()
    asteroid_layer:addChild(s) s:sp(w/2+sin(rad(a))*max(w,h)*0.6, h/2+cos(rad(a))*max(w,h)*0.6) s:addEventListener(Event.ENTER_FRAME, function()move(s,1) cc(s) end)
    end
    function wait_for_player() waiting_for_player=1 msg("Tap to Play",1) end
    function start_game()
    go=null level=1 asteroid_rate=1 gravity_level=1 asteroid_size=1 asteroid_trajectory_factor = 0 score=0
    while asteroid_layer:getNumChildren()>0 do local c=asteroid_layer:getChildAt(1) c:removeAllListeners() c:removeFromParent() end
    ship.vx,ship.vy=0,0 ship:sp(w*0.1, h*0.1) ship:sr(-45) stage:addChild(ship) ship:setScale(1) ship.collapsing=null
    Timer.delayedCall(1000,function()tip("Touch To Turn", "l")end) Timer.delayedCall(5000,function()tip("Touch To Turn", "r")end)
    Timer.delayedCall(9000,function()tip("Touch To Burn")end) Timer.delayedCall(13000,function()tip("Avoid the Black Hole")end)
    Timer.delayedCall(17000,function()tip("Avoid the Asteroids")end)
    end
    wait_for_player()
    function end_game() if not go then go=1 msg("Game Over", 1) Timer.delayedCall(5000, wait_for_player) if tiptf then tiptf:removeFromParent() end end end
    function move(o,g) -- Move the object, applying decceleration, with optional gravity
    if o.collapsing then
    o.collapsing = o.collapsing * 0.9 o.vx,o.vy=0,0 local x,y=o:gp() o:sp(cx+(x-cx)*o.collapsing,cy+(y-cy)*o.collapsing)
    o:setScale(o.collapsing) if o.collapsing < 0.01 then o:removeFromParent() end
    end
    o.vx=o.vx or 0 o.vy=o.vy or 0 local ox,oy = o:gp() if o.vr then o:sr(o:gr()+o.vr) end
    local d = sqrt((ox-cx)*(ox-cx)+(oy-cy)*(oy-cy)) local ge = min(1/max(d,1), 100) * 2 * gravity_level
    if g then local a=rad(angle_between_points(ox, oy, cx, cy)) o.vx+=sin(a)*ge o.vy+=cos(a)*ge end
    df=0.995 o.vx,o.vy=o.vx*df,o.vy*df o:sp(ox+o.vx, oy+o.vy)
    if o.size and d < o.size/2 + bhsize/2 then o.collapsing=o.collapsing or 1 if o==ship then end_game() end end
    end
    function add_exhaust(side) -- Show the thrust from both nacelles
    local ang = -ship:gr() + 35 if side == "l" then ang-=35*2 end local sx,sy,l=ship:gp()
    local ex, ey, s = sx + ship.size*0.63*sin(rad(ang)), sy + ship.size*0.63*cos(rad(ang)), Shape.new()
    s:setLineStyle(2, 0xff5000) s:moveTo(-5,0) s:lineTo(5,0) s:endPath() s:sp(ex,ey) s:sr(ship:gr()) exhaust_layer:addChild(s)
    s.life, s.vx, s.vy = 1, ship.vx, ship.vy
    s:addEventListener(Event.ENTER_FRAME, function() s.life-=0.02*rand(0.9,1) if s.life<=0 then s:removeFromParent() else s:setAlpha(s.life/4)
    s:setScale(min(5, 1/s.life)) move(s) end end )
    end
    function bs()
    local sx, sy = ship:gp() local x, y, w, h = ship:getBounds(ship) local rt=RenderTarget.new(w,h)
    ship:sp(0-x, 0-y) rt:draw(ship) ship:sp(sx, sy) local np = 5
    for i = 1, np do local s = Shape.new() s:setLineStyle(0,0xff0000) s:setFillStyle(Shape.TEXTURE, rt) local x1, y1 = rand(1, w),rand(1,h)
    s:moveTo(sx, sy) for j=1,3 do s:lineTo(rand(1, w),rand(1,h)) end s:lineTo(x1, y1) s:endPath() asteroid_layer:addChild(s) s.size=h s:sp(sx+x, sy+y)
    s.vx, s.vy,s.vr=ship.vx+rand(-10,10)* 0.1,ship.vy+rand(-10,10) * 0.1,rand(-10,10)*0.1 s:addEventListener(Event.ENTER_FRAME, function()move(s,1) end) end
    ship:removeFromParent()
    end
    stage:addEventListener(Event.ENTER_FRAME,
    function()
    if waiting_for_player then return end
    local rs,thrust = 3,0
    if left_touches > 0 then ship:sr(ship:gr()-rs) thrust=0.5 end if right_touches > 0 then ship:sr(ship:gr()+rs) thrust=0.5 end
    if (left_touches > 0 or middle_touches > 0) and not go then add_exhaust("r") end if (right_touches > 0 or middle_touches > 0) and not go then add_exhaust("l") end
    if middle_touches > 0 then thrust=1 end
    local sr, tf = ship:gr(), 0.05 if not go then score+=1 score_tf:setText(string.format("SCORE: %d",score)) end
    if rand(0,1000)<(asteroid_rate + 1)*5 then make_asteroid() end ship.vx+=sin(rad(sr))*thrust*tf ship.vy-=cos(rad(sr))*thrust*tf move(ship,1)
    local x,y=ship:gp() if x<1 or x>w or y<1 or y>h then ship.vx, ship.vy =0,0 ship:sp(min(w,max(1,x)), min(h,max(1,y))) end
    if score%ppl==1 then level=floor(score/ppl)+1 local nfi=(level+#dfs-1) % #dfs + 1 local txt="Level " .. level if level > 1 then txt=txt .. ": " .. dfs[nfi] end msg(txt)
    if nfi==1 then asteroid_rate+=1 elseif nfi==2 then asteroid_size+=1 elseif nfi==3 then gravity_level+=0.25 elseif nfi==4 then asteroid_trajectory_factor += 0.2 end end
    end)
    left_touches, right_touches, middle_touches = 0,0,0 -- Keep count of touches on left, middle, center
    function ntouches(zone,n) if zone=="l" then left_touches+=n elseif zone=="r" then right_touches+=n elseif zone=="m" then middle_touches+=n end end
    function setzone(event)
    local zone if event.touch.xw*2/3 then zone="r" else zone="m" end
    if event.zone ~= zone then ntouches(event.zone,-1) event.zone = zone ntouches(event.zone, 1) end
    end
    stage:addEventListener(Event.TOUCHES_MOVE, setzone)
    stage:addEventListener(Event.TOUCHES_BEGIN, function (event) event.zone=null setzone(event) if waiting_for_player then waiting_for_player = nil start_game() end end )
    stage:addEventListener(Event.TOUCHES_END, function (event) ntouches(event.zone, -1) end )
  • PaulHPaulH Member
    Here's the source file
    lua
    lua
    main.lua
    9K
    +1 -1 (+5 / -0 )Share on Facebook
  • PaulHPaulH Member
    edited May 2023
    I'm having trouble getting the code tag to mark it up correctly. Any tips?

    I see I'm way, way over the 3K character goal, almost triple that. Now I've got it down to around 6k, but I'll never get it to 3K without cutting into the gameplay.

Sign In or Register to comment.